クライアントサイドJavaScriptでのビューの作り方4つ

追記: 指摘により、UIオブジェクト型を追加した(thx @kanreisa)。

クライアントサイドJavaScriptでのビューの作り方を大別すると、3つ4つある。

  • DOM操作型
  • テンプレートエンジン型
  • UIオブジェクト型
  • データバインディング

ここでいうビューの作り方とは、有り体にいうとJavaScriptからどうやってDOM要素を生成したりするかどうか。イベントリスナーの登録とかも含む。

DOM操作型

昔ながらのやり方。jQueryとか使って直接DOM操作してビューを作る。

// 例えば、<div class='hoge'>fugafuga</div> みたいなDOMを表示する
var myView = $("<div class='hoge'/>");
myView.text('fugafuga');

// body以下に挿入
$(body).append(myView);
  • 長所
    • 誰でも意味はわかる
  • 短所
    • 読みづらいし書きづらいのでメンテナンス性低い
    • コード量が無駄に多くなる傾向

テンプレートエンジン型

テンプレートエンジンが世の中にはあるのでそれを使う。HTMLでそのままビューのひな形を書けて、データをJavaScriptから嵌めこむ。

下の例ではPUREというライブラリを使っている。

<!-- ここがテンプレート -->
<div class="template">
  Hello <a></a>
</div>

<script>
  var jsonData = {
    who: 'BeeBole!',
    site: 'http://beebole.com'
  },

  //template commands
  directive = { 'a':'who', 'a@href':'site' };
  //select the template and transform it
  $('div.template').render(jsonData, directive)
</script>
<!-- http://beebole.com/pure/documentation/get-started/ から引用 -->
  • 長所
  • 短所
    • ビューに用いるデータを更新するたびにテンプレートエンジンの描画メソッドを叩く必要がある
    • テンプレートエンジンによってはイベントリスナーの登録をサポートしていない

UIオブジェクト型

jQuery UIExt.jsのような、DOM操作を隠蔽してくれるようなオブジェクトを作ってくれるライブラリを利用する。Ext.jsなど、内部ではテンプレートエンジンを使っていたりする場合もある。

// Ext.jsでのタブパネルを表示する例: http://cdn.sencha.io/ext-4.1.1a-gpl/docs/index.html#!/api/Ext.tab.Tab
Ext.create('Ext.tab.Panel', {
    width: 400,
    height: 400,
    renderTo: document.body,
    items: [{
        title: 'Foo'
    }, {
        title: 'Bar',
        tabConfig: {
            title: 'Custom Title',
            tooltip: 'A button tooltip'
        }
    }]
});
  • 長所
    • DOM操作を意識しなくても良い
    • あらかじめコンポーネントの挙動なども構築されている
  • 短所
    • DOM操作が隠蔽されているために実際にはどういう風にDOM操作されているのかわかりづらい
    • そのためカスタマイズしたり詳細をいじったりしづらい

データバインディング

モデルをバインドすると、モデルの更新を自動的にビューに反映したりしてくれるやつ。JavaScriptのモデルをいじると勝手にビューに反映してくれるだけではなく、DOM側の変更を自動的にモデルに反映してくれたりするものもある。

MVVMフレームワークKnouckout.jsとかAngular.jsみたいなフレームワークに備わっている仕組み。Win8メトロアプリをJavaScriptで作る際に提供されるライブラリ、WinJSでも採用されている。単体のライブラリだとjsViewとか使う。

実際のコードは、一見テンプレートエンジンを使ったやり方と変わらなく見えるが、モデル(正確にはビューモデル)のデータとビューが自動的に連動するようになる。下の例はknockout.jsを使ったもの。

<div class='liveExample'>   
    <p>First name: <input data-bind='value: firstName' /></p> 
    <p>Last name: <input data-bind='value: lastName' /></p> 
    <h2>Hello, <span data-bind='text: fullName'> </span>!</h2>  
</div>

<script type='text/javascript'>//<![CDATA[ 
var ViewModel = function(first, last) {
    this.firstName = ko.observable(first);
    this.lastName = ko.observable(last);
    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);
};
 
var viewModel = new ViewModel("Planet", "Earth");
ko.applyBindings(viewModel); // <= viewModelをいじると自動的にDOM要素に反映されるようになる
</script>
  • 長所
    • データ更新したら勝手にビューも更新されて便利
    • コード量が少なくなる
    • 一番かっこいい
  • 短所
    • 仕組みを理解する必要がある

まとめ

用途にあったものを使いましょう。DOM操作でなんとかするやり方は規模が大きくなると最終的には誰も幸せにならないので他の選択肢を検討しましょう。それなりにリッチなものを作るならデータバインディング型も検討しましょう。