Backbone.js の開発環境を構築し MVCパターンで書いてみた


これまで個人的に AngularJS、Knockout.js、Vue.js そのほか諸々を試してきたのですが、まだ Backbone.js はちゃんと触ってないな〜ということで試してみました。

今回は Yeoman の backbone ジェネレータを利用しました。ジェネレータを利用した理由としては、初めてなのでベストプラクティスっぽい構成をまずは知りたかったのと、CoffeeScript で書くための環境を、手軽に作りたかったからです。

Yeomanの ジェネレータを利用すると Grunt/Bower まわりの環境がある程度そろうので楽です。

環境構築

前提

  • 手元の OS:Mac OS X 10.9.5 (Mavericks)
  • Yeoman、Grunt、Bower を使います。もしまだインストールしていない場合、こちらの投稿を参考にインストールしてください。
  • bacbone ジェネレータをインストールしていない場合は、次のようにインストール。

    $ npm install -g generator-backbone
    
  • 結果的に今回、利用したツール/ライブラリ郡の細かいバージョンは次のとおり。

    • Yeoman:1.3.3
    • Yeoman の generator-backbone:0.3.3
    • Backbone.js:1.1.2
    • JQuery:2.1.1 .. Backbone.js はこれに依存している
    • Lo-Dash:2.4.1 .. Backbone.js はこれに依存している

手順

  • ジェネレータを起動します。

    $ yo backbone
    

    今回は CoffScript だけを選択しました。

  • 雛型生成がおわった直後は、JavaScriptライブラリ類が入っていないようなので、更に Bower でインストールします。

    $ bower install
    
  • 次のようにファイルが展開されました。

  • ここで動作確認します。

    $ grunt serve
    

Backbone.js で書いてみる

Backbone.js の主要なコンポーネントは Model Collection View Router です。この Yeoman の環境では、それぞれ次のような生成コマンドが用意されています。

$ yo backbone:model hoge
$ yo backbone:collection hoge
$ yo backbone:view hoge
$ yo backbone:router hoge

そのほか backbone ジェネレータの説明は、GitHubで確認できます。
https://github.com/yeoman/generator-backbone

今回は最低限で ModelView だけ使ってみます。

$ yo backbone:model hoge_model
$ yo backbone:view hoge_view

すると、次のように ModelView の雛型が生成されます。

こっからソースを書いていきます。結果からいうと、こういう簡単なものを作ります。

Backbone.js の思想?に従って ユーザ入力はコントローラ経由でモデルへ反映し、ビューはモデルの変更を検知して自身の表示内容を変更 という風にします。

今回のソースは GitHub にも置いてあります。
https://github.com/hkusu/Backbone.js_demo

Model の作成

ほぼ雛型のままなのですが、今回あつかう2つの値 name age のデフォルト値(空)を設定します。

app/scripts/models/hoge_model.coffee
'use strict';

class BackboneTest.Models.HogeModel extends Backbone.Model
  url: ''

  initialize: () ->

  defaults:
    name: ""
    age: ""

  validate: (attrs, options) ->

  parse: (response, options) ->
    response

View と テンプレートの作成

ややこしいのですが、Backbone.js でいう View は、他のフレームワークでいいう コントローラ です。

まずテンプレートから。表示部分は <$= ほげほげ %> で変数を記載します。入力部分は、あとで jQuery で input タグを拾うのでソース上は何もしませんが、本当は id や class を指定した方が良いかも。

app/scripts/templates/hoge_view.ejs
<p>
  名前:<%= name %>
</p>
<p>
  年齢:<%= age %>
</p>

<hr>

<p>
  新しい年齢:<input type="text" />
  <br>
  <font size="1px" color="orange">
    Model へ反映  自動的に View へ反映されるデモです。<br>
    ただリアルタイムデータバインドが聞いてないのでカーソル外してください..</font>
</p>

次は View(他のフレームワークでいうコントローラ)を書きます。追加したのは eventinput タグの変更を拾うところ(= コントローラの役割)と、inputCange メソッドです。

注意すべきことは、

  • inputCange メソッドでは、Model を更新しています。
  • listenTo で Model の変更を監視し、変更があった場合は再描写しています。
app/scripts/views/hoge_view.coffee
'use strict';

class BackboneTest.Views.HogeView extends Backbone.View

  template: JST['app/scripts/templates/hoge_view.ejs']

  tagName: 'div'

  id: ''

  className: ''

  events:
    "change input": "inputCange"

  inputCange: () ->
      @model.set("age", @$("input").val())

  initialize: () ->
    @listenTo @model, 'change', @render

  render: () ->
    @$el.html @template(@model.toJSON())

全体を統合する

この View をブラウザへ表示するために、index.html に div タグを仕込み、

app/index.html
<div id="hoge"></div>

最後に main.coffee で、

  • Model と View をインスタンス化
  • View を index.html へ差し込み
  • View と Model の紐付け

をします。

app/scripts/main.coffee
window.BackboneTest =
  Models: {}
  Collections: {}
  Views: {}
  Routers: {}
  init: ->
    'use strict'

    model = new @Models.HogeModel(
        name: "山田 太郎"
        age: 31
    )

    view = new @Views.HogeView(
      el: $("#hoge")
      model: model
    )

    view.render()

    return

$ ->
  'use strict'
  BackboneTest.init();

デモはこちらに置きました(GitHub Pages)。
http://hkusu.github.io/Backbone.js_demo/dist/

おわりに(Backbone.js に対する感想)

前々から聞いてはいたのですが、一つのことを実現するのに色々なところに記述を書く必要があるなあと感じた反面、フレームワークで縛られるので、実現方法が統一されるなと。

また、モデルがしっかり書けるな、と思いました。サーバサイドのモデルと連携 & かっちりデータ構造が定義されるシステムに向いているのでは。

View まわりは単体だと少し弱い(jQueryを直接いじってる気分になる)と思ったのですが、他のライブラリと組み合わせたり、Marionette.js を使えばそこは解消されるんだろうなと思いました。