読者です 読者をやめる 読者になる 読者になる

Carpe Diem

備忘録。https://github.com/jun06t

Backbone.js で MVC

Backbone.jsを用いてクライアントサイドMVCを実現する簡単なサンプルを紹介します。
JavaScript徹底攻略 (WEB+DB PRESS plus)JavaScript徹底攻略 (WEB+DB PRESS plus)
(2013/01/26)
沖林 正紀、吾郷 協 他

商品詳細を見る
という書籍を参考にしています。前半は説明、後半はサンプルソースを用いて確認、と言った流れです。 説明は要らない人は後半から見るといいです。 ==============================前半============================= ◆Backboneの主要クラス Backbone.jsのMVCイメージは以下です。 backbone1.gif ・Backbone.Model Key-Value型のデータを保持するモデル。データは通常JSON APIを通してサーバから受け取ったものを扱います。 ・Backbone.Collection 一連のモデルを扱うためのクラス。コレクションはモデルを配列のようにグループ化して保持します。 ・Backbone.VIew モデルの格納されたデータを表示するためのクラスです。HTMLを描画したり、モデルの変更やDOMのイベントを監視してHTMLを更新する役割を持ちます。 HTMLを構築するためのテンプレートエンジンは持っていませんが、Underscore.jsに含まれるテンプレートエンジンや、任意のテンプレートエンジンを使えます。 実質的にこのビューがコントローラをかねます。 ・Backbonee.Router URLのハッシュフラグメント(#以降)を管理するためのクラスです。Ajaxではページ遷移がないので、こういったハッシュで管理することが多いです。 ◆Backbone.jsを使うメリット実装を分離し構造化できる 上記のようにクラスがしっかり分かれているので、「モデルはデータの懸賞とサーバの通信を担当」「ビューは表示周りとロジックのみ集中」などの分離ができます ・ビューとモデルをイベントで繋げられる Backbone.jsには、ビューとモデルを簡単に最新の状態に同期できる仕組みがあります。ビューはモデルの変更をイベントにより監視できるので、表示を更新する処理が散らばらずに済みます。またモデルから常に最新のデータを取得できるので、DOMにデータを埋め込む必要もないです。 ・多様なイベント管理の仕組みがある ビューのeventsプロパティでイベントハンドラを管理し、モデルへのbindもビューで設置します。この管理がシンプルなため、少ないコードでイベントハンドラを管理出来ます。これはソースを見ると早いです。 =============================後半============================= 以下サンプルコードを用いた後半です。サポートサイトからファイルをダウンロードしてください。 下の方の一般記事の「Backbone.jsでMVCパターン」です。 サポートサイト サンプルコードはアドレス帳です。 中には index.html と js/ には
ファイル説明
addressbook.jsアドレス帳の実装
backbone.jsメインライブラリ
backbone.localStorage.jsAPIからデータを保存・取得する処理をlocalStorageを使うように置き換えるアダプタ
jquery-1.8.3.jsBackbone.Viewクラスが依存
underscore.jsjQueryのようなユーティリティライブラリ
が入っています。index.htmlをダブルクリックするとどういう物か分かると思います。 ◆モデルの作成 Backbone.Modelを継承します。この中に多くのメソッドがあるので、これを継承すれば最小限のオーバーライドだけでモデルを作成出来ます。
    var Address = Backbone.Model.extend({
        // デフォルト値
        defaults: {
            name: ''
        },
        // 初期化
        initialize: function () {
            if (!this.get('name')) {
                this.set({name:  this.defaults.name});
            }
        },
        // バリデーション
        validate: function (attributes) {
            var name = attributes.name;
            if (!name || name === this.defaults.name) {
                return 'Error!';
            }
        }
    });
基本的にdefalus、initializeをオーバーライドします。setを使うときはソースのようにvalidateをオーバーライドして値の検証をします。 ◆コレクションの作成
    // Backbone.Collectionを継承したAddressCollectionクラスを定義
    var AddressCollection = Backbone.Collection.extend({
        // このCollectionで扱うModel
        model: Address,
        // addressbook-sampleというキーでローカルストレージを使う
        localStorage: new Store('addressbook-sample')
    });
    // インスタンスを生成
    var Addresses = new AddressCollection;
Backbone localStorage Adapterを使うため、APIのURLを指定する代わりにlocalStorageを指定しています。 ◆アイテム用ビューの作成
    // Backbone.Viewを継承してAddressを表示するAddressViewクラスを定義
    var AddressView = Backbone.View.extend({
        tagName: 'li',
        className: 'address-item',
        // イベントハンドラの設定
        events: {  // ①
            'dblclick label.name': 'rename',
            'click button.delete': 'clear'
        },
        initialize: function () {
            // モデルへのバインド
            this.model.bind('change', this.render, this);   // ②
            this.model.bind('destroy', this.remove, this);  // ②
        },
        render: function () {  // ③
            $(this.el).html(
                $('
Backbone.Viewを継承し、いくつかのメソッドをオーバーライドしてます。 eventsプロパティでイベントハンドラを設定します。 イベント名 セレクタイベントハンドラ と書きます。イベント名とセレクタの間は半角スペースです。 initializeをオーバーライドすることでモデルへのバインドをしています。 changeやdestroyといったイベントはBackbone.Viewにあります。 renderメソッドをオーバーライドしてDOMを構築する処理をいれます。 ◆一覧用ビューの作成
    // アプリケーション全体を表示するAppViewクラスを定義
    var AppView = Backbone.View.extend({
        el: $('#app'),  // ①
        events: {
            'keypress #new-address': 'keyPress',
            'click #delete-all': 'deleteAll'
        },
        initialize: function () {
            this.input = this.$('#new-address');
            // Collectionへのバインド
            Addresses.bind('add', this.add, this);
            Addresses.bind('reset', this.addAll, this);  // ②
            // モデル一覧の取得
            Addresses.fetch();  // ③
        },
        add: function (address) {
            // 引数のモデルからAddressViewを作成・描画
            var view = new AddressView({model: address});
            this.$('#list').append(view.render().el);
        },
        addAll: function () {
            Addresses.each(this.add);
        },
        keyPress: function (e) {
            if (e.keyCode === 13) {
                // Enterキーが押されたらモデルを追加する
                Addresses.create({name: this.input.val()});
                this.input.val('');
            }
        },
        deleteAll: function (e) {
            var address;
            while (address = Addresses.first()) {
                address.destroy();
            }
        }
    });
    // インスタンスを生成
    var App = new AppView;
AddressViewと違い、jQueryにidセレクタを渡して直接elプロパティを指定しています。 AddressViewではメソッドをモデルにバインドしていましたが、AppViewではコレクションにバインドします。 ソース: JavaScript徹底攻略 MVCパターンでアプリケーションを構築する