前提
会社(Quipper)で今からこういう風にしたい、と宣言した社内ドキュメントを公開する。
枯れてるわけではない。
- coffeescript
- Backbone
- Backbone.stickit (データバインディング)
- Chapling.js(は、オマケなのでどうでもいいがサンプルコードはこう)
backbone.stickitは安心と信頼のNYT製。(実質Backbone作ってるDocumentCloudと一緒のところ?)
backbone.stickit
目的
データバインディングを全面的に使って再描画を最小限にし、コードの見通しをよくしたい。
モデルの役割を明示的にし、MVVMを導入する。
理想的なAPI
擬似コード
# ビューモデルの定義
class TopicViewModel extends Model
defaults:
title: '' # たぶんここでパラメータ名(と仮でもいいので初期値)を書いておくと見通しがよい
# topic.hbs
"""
<span class="title"></span>
"""
# !!! テンプレートはビューモデルにのみ依存してテンプレートを展開する
# getTemplateDataは可能な限り使わない
# controller
...
show: ({topic_id})->
# Collectionから紐付いたものをとってくる。Collectionの中身は事前に初期化されている。
# Railsのコントローラに近いイメージでモデルを取得できるようにしておく
# Modelの役割を本来の意味でのモデルに近づける
topic = Topics.find {topic_id} #=> Backbone.Collectionはlodashのメソッドをmixinしているのでこういう風に書ける
# fetchが必要かどうかはモデル次第。Topicに関しては最初に初期化しておきたい
# 各種モデルを用いてビューモデルを組み立てる
# ViewModelクラスはBockbone.Modelを継承しているがRESTを叩いたりはせず、ビューの振る舞いだけに興味がある
topicViewModel = new TopicViewModel
title: topic.title
@compose 'topic', new TopicView model: topicViewModel
# controllerが各種イベントに対するハンドラをもつ
@subscribeEvent 'updateTopicTitle', (title) ->
topicViewModel.set 'title', title #=> バインディングがあるのでビューも更新される
# 仮にビューバインディングで対応できない系(大域に渡る処理)のものは、ある程度受け入れる
@subscribeEvent 'changeContainerView', ($div) ->
@$('.content').html $div
# 基本的にイベントは受け取るものは、コントローラで処理する
# コントローラが膨らむ場合は適宜モデルロジック、ビューロジックに移す
# view
# getTemplateDataは可能な限り使わず、ビューモデルにだけ依存する
class TopicView extends View
# model -> TopicViewModel
bindings:
'.title': 'title'
# ビューに特有な値はonSetなどを用いて生成する
# ビューイベントをイベント名を翻訳して、コントローラへ向けて発火する
render: =>
super
@stickit()
# イベントハンドラはrender後に書く
@delegate 'click', '.i-want-to-change-topic-title-to-hoge', => #雑…
# コントローラが知るべきものはコントローラに向けてイベントを発火する
@publishEvent 'updateTopicTitle', 'hoge'
これによって可能になるもの
- サーバーサイドのモデルのコピーと、ビューに紐づくモデルを一貫させ、コードの見通しをよくする。
- パラメータの書き換えを最小限に抑え、再描画を抑えパフォーマンスがよくなる
- ビューの変更はビューモデルを通じて行う
- テストはビューモデルの変更に対して行う(ビューモデルによって生成されるビューには感知しない) #=> DOMに触れずに済む
- テンプレートはビューモデルに一意に依存するので、使えるパラメータが明示的になる
ビューモデルはフロントに近い存在なので、多少汚くてもいい。新しく作る概念なので、ある程度闇を引き受けてもらう。
いままでふわっとした扱いだったModelを明示的に取り回したい。