Backbone.js + jQueryMobile(1.4.5) でアプリ作ったメモ

表題の通り簡単なアプリ作ったのでメモっておく。

https://github.com/Tenderfeel/MobMap

Q: なぜ今頃BackboneにjQueryMobileなのか?ナウいのはReactだべ?
A:
1. 異動したプロジェクトがBackboneベースだったので復習する必要があった。
2. UIとか自前で用意するのが面倒だった。(特にアニメーション)

jQueryMobileのlocation.hash監視をオフにする

Backbone.jsとjQueryMobileは一部機能が被ってる所がある。何かというと、location.hashを監視してあれこれする所です。
同じような機能2つも平行して走らせる必要はないので、操作のしやすいBackbone.jsのRouter機能を使用することとして、jQueryMobileの設定でlocation.hashの監視まわりをオフにした。

  $(document).bind("mobileinit", function () {
    $.mobile.hashListeningEnabled = false;
    $.mobile.linkBindingEnabled = false;
    $.mobile.ajaxEnabled = false;
  });

下2つは pagecontainer Widget の冒頭(Ajax page navigation)に書いてある設定。

Backbone.jsのRouterでjQMのpageを切り替える

jQueryMobileでの基本的なpageの作り方はdemoのドキュメントに書いてある通りで、
data-role=pageな要素を用意するか、

<div data-role="page">
</div>

APIのpage widgetを直接叩いて作るかになる。

$( ".selector" ).page();

このようなjQueryMobile的に作られたpageが3つくらいあったとして、
それをBackbone.jsのRouterで表現すると次のようなソースになる:

var Router = Backbone.Router.extend({

  routes: {
    '': 'homePage',
    "a": "aPage",
    "b": "bPage"
  },
   
  initialize: function() {

    Backbone.history.start();
    
  },
   
   homePage: function() {
   },

   aPage: function() {
   },

   bPage: function() {
   }
   
 });

前述の設定でjQueryMobileのhash監視をオフにしているので、リンクを設置してクリックしても当然動かないが、
routesのbindingした関数の中で、pagecontainer Widgetのchangeメソッドを叩けば:

$( ":mobile-pagecontainer" ).pagecontainer( "change", "#home" );

元の挙動にすることができる。

Backbone.jsのViewを使用したpage生成

アプリではやってないが、jQueryMobileのpageをJSで生成するとして、Backbone.Viewを使ったらこうなるっていう簡単なサンプル。

Toolbar Widgetはデフォルトがfooterとして生成されるので、headerにしたい場合は属性でdata-role="header"を指定しなければならない。(なぜかoptionで設定できない)

$('<div data-role="header"></div>').toolbar(); //-> header
$('<div></div>').toolbar(); // -> footer

Backbone.Viewでpage Widgetを呼ぶならinintalizeとかrenderで$el.page()すればいい。

    render: function() {
        this.$el.page();
        return this;
    }

Toolbar WdigetのオプションでaddBackBtn: trueすると戻るボタンが追加されるが、hashの監視をオフにしているとボタン押しても何も起きないので、Backbone.View側で処理を追加する。

events: {
   'click .ui-toolbar-back-btn': 'handleBackBtn'
}

ViewでBackbone.Routerのメソッド実行するならグローバルなオブジェクトにインスタンス保存しておく必要がある。
それが気持ち悪いと思うならlocation.hash操作するのが手軽だと思う。

handleBackBtn: function() {
   //window.router.navigate('', {trigger: true}); //Router呼ぶ
   location.hash = ''; //hash操作する
}

Backbone.Router.navigateを使用する場合に、pagecontainer(‘change’)を実行しているメソッドが対象になる時はtriggerをtrueにしておくこと。

テンプレートからWidget作成

WidgetのHTMLそのままテンプレートにしてもいいし、API叩いて作成してもいい。
以下はページAのヘッダーとフッターをテンプレートから作るように変更したサンプル:

Backbone.jsで使えるtemplateはそのままUnderscore.jsのtemplateだが、
Underscore.jsのtemplateは自由度高すぎて分離する概念が消失することがままあるので、
Handlebars.jsくらい出来ることに制限がある方が美しい世界を維持出来るように思う。
サンプルでは一応両方書いといたが、テンプレートライブラリが返すのはfunctionであり、それに引数でデータを渡して実行するとHTMLが返されるという基本は何使っても変わらない。

    
headerTemplate:_.template($('#header-template').html()),
    
footerTemplate: Handlebars.compile($('#footer-template').html()),
    

footerはToolbar Widgetの中にNavbar Widgetが入っているという入れ子構造なので、headerと同じように$('').toolbar()すると挙動が狂う(append先がbodyになる)ため、何もしない。

this.header = $(this.headerTemplate({title:'A'})).toolbar({
            theme: 'b',
            addBackBtn: true
        });
this.footer = this.footerTemplate({});

※headerも全部テンプレートに記述してしまえばAPI叩く必要はない

Leave a Comment.