Backbone でモバイル版の UI を作っていて、 Facebook や Gmail の iPhone アプリみたいな、 スライド表示されるメニューを実装したくなった。
そういったメニューを実装するための jQuery プラグインは既にいくつか存在していて、
あたりを試してみたけど、どれもシックリこない。
そんな中、最近 jQuery.mmenu っていう jQuery プラグインを知った。
触ってみた感じ、自分が求めているものに一番近い。今のところは。
そこで jQuery.mmenu と Backbone の組み合わせに挑戦。 Backbone と jQuery.mmenu を組み合わせたサンプルは次の通り。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>MMenu Backbone Sample</title> <link rel="stylesheet" href="mmenu.css" /> <link rel="stylesheet" href="examples.css" /> </head> <body> <div id="main"> <div id="header"> <a href="#menu"></a> MMenu Backbone </div> <div id="content"> </div> <nav id="menu"> <ul></ul> </nav> </div> <script id="menu_template" type="text/template"> <a class="menu-title" href="#/menu/<%= id %>"><%= name %></a> </script> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.mmenu.js"></script> <script type="text/javascript" src="underscore.js"></script> <script type="text/javascript" src="backbone.js"></script> <script type="text/javascript"> var Menu = Backbone.Model.extend({ defaults: { id: 0, name: "" } }); var MenuCollection = Backbone.Collection.extend({ model: Menu }); var Main = Backbone.Model.extend({ defaults: { selectedMenu: null }, initialize: function() { this.menus = new MenuCollection(); }, selectedMenu: function() { return this.get("selectedMenu"); }, selectMenu: function(id) { var menu = this.menus.get(id); this.set("selectedMenu", menu); } }); var MenuView = Backbone.View.extend({ template: _.template($("#menu_template").html()), tagName: "li", events: { "click a.menu-title": "onClick" }, render: function() { var json = this.model.toJSON(); var html = this.template(json); this.$el.html(html); return this; }, onClick: function(e) { // メニューをクリックされたら手動で閉じる $("#menu").trigger("close"); } }); var MainView = Backbone.View.extend({ el: $("#main"), initialize: function() { this.model.on("change:selectedMenu", this.renderContent, this); }, render: function() { this.renderMenu(); return this; }, renderMenu: function() { var $ul = this.$el.find("#menu>ul"); $ul.empty(); this.model.menus.each(function(menu) { var view = new MenuView({ model: menu }); view.render(); $ul.append(view.el); }, this); }, renderContent: function() { var $content = this.$el.find("#content"); $content.empty(); var menu = this.model.selectedMenu(); if (!menu) { return; } $content.append(menu.get("name")); } }); var MainRouter = Backbone.Router.extend({ routes: { "menu/:id": "showMenu" }, initialize: function() { // サンプルメニューを作成 this.main = new Main(); for (var i = 0; i < 20; i++) { this.main.menus.add({ id: i, name: "Menu" + i }); } this.mainView = new MainView({ model: this.main }); this.mainView.render(); }, showMenu: function(id) { this.main.selectMenu(id); } }); $(function() { window.router = new MainRouter(); Backbone.history.start(); // メニューをクリックして自動で閉じると // location.hash が #menu になってしまうので // メニューをクリックして自動で閉じないようにしておく。 $("#menu").mmenu({ closeOnClick : false }); }); </script> </body> </html>
ブラウザで表示してみた。
左上のボタン?をクリックして、メニューを開いてみる。
メニューをクリックすると
メニューが閉じて、選択したメニューの名前が表示された。
jQuery.mmenu の自動開閉を有効にしていると、localtion.hash が #menu になってしまい、Backbone の Router が反応してくれなくて嵌った。使い方はシンプルだから、スンナリ実装できると思っていたんで、予想外の躓きだったな。