みなさんこんにちは。江口です。
前回のエントリで予告したとおり、今回は MVVM パターンを利用して動的な UI を作成することのできる JavaScript ライブラリ「Knockout」について紹介します。
Knockout とは
Knockout は主な特徴として
- 宣言的バインディング
- 自動 UI 更新
- 依存性追跡
- テンプレート
という4つのコンセプトを謳った JavaScript のライブラリです。このコンセプトの中で特に重要となるのは「宣言的バインディング」と「自動 UI 更新」になります。
この機能を利用することで、下の例のように UI 上の更新したい要素を id や class 属性の指定などを指定して探しだしてから変更するようなコードは必要なくなります。Knockout を使うと ViewModel 内の変数を単純に書き換えるだけで、その変数と結びついた要素が自動的に変更されるようになります。
下の例は非常にシンプルな例なので Knockout を使うメリットはほとんどありませんが、もっと大規模なアプリケーションなってきた時には大きな効果を発揮します。
<div id="issuecard"> <span></span> <span></span> </div> jQuery('#issuecard .summary').text('newValue');
<div id="issuecard"> <span data-bind="text: summary"></span> <span></span> </div> var vm = { summary: ko.observable('') }; ko.applyBindings(vm); vm.summary('newValue');
Knockout 自体は MVVM パターンを利用したよる実装を JavaScript 上で実現するためのライブラリであり、Angular.js や Ember.js などの「フレームワーク」を謳っている JavaScript ライブラリのように、モデルやコントローラを作るのを補助するような仕組みは提供されておらず、守らなければならない約束事も多くはありません。
そのため、利用方針を自分で考える必要がありますが、必要な機能だけを自由に使うことができます。そのため、既存のアプリケーションに組み込むような場合でも、アーキテクチャの変更などを行わずに組み込んでいくことも比較的容易になっています。また、小さなアプリケーションであれば必要最小限の機能だけを使うことで、シンプルに実装を行うことができます。
なお、Knockout には標準の機能を拡張したり新しい機能を追加する仕組みが用意されています。この仕組みを利用することで、必要な機能を追加してより便利に利用することができます。これらの機能を活用することで、Backlog のまとめて操作機能のようなシングルページアプリケーションを始めとした動的な UI を持つアプリケーションを比較的シンプルなコードで実現することができるようになります。
なお、Knockout 自体は jQuery といった他のライブラリに依存しないため Knockout 本体を読みこませるだけで使用することができます。
MVVM パターンについて
ここまでで 「MVVM パターン」という単語が何度か登場していますが、 これはよく知られている MVC(Model-View-Controller) パターンや MVP(Model-View-Presenter) パターンなどと同く、GUIアーキテクチャパターンの一つです。これは、バインディングの仕組みを活かすのに適したアーキテクチャパターンになっています。
MVVM パターンでは Model / View / ViewModel の部分にアプリケーションを分割して設計・実装を行います。アプリケーションの構造を次のの3つの責務に分割します。
- View (UI の外観と構造)
- ViewModel (View と Model 間の隔たりの吸収)
- Model (アプリケーションの本質に関わる部
このように責務を分割することでコードの見通しをあげられるため、コードの理解や変更が容易になるというメリットがあります。また、テストしにくい UI に関する部分を分離することで、Model 部分がテストしやすくなります。
Knockout の場合では具体的に、HTML/CSS (View) と JavaScript オブジェクト (ViewModel / Model) のように分割することができます。
View
MVVM パターンでは、View に表示する情報の状態や振舞いを ViewModel が持っています。View は単純に UI の構造や外観を表し、そこに ViewModel の状態を映し出すというのが大きな特徴です。
Knockout では、HTML 中の要素に data-bind 属性を宣言することで、View と ViewModel のデータとを結びつける(バインド)ことが宣言的に出来るようになっています。また、HTML 中の要素から発生するクリックを始めとする様々なイベントなども ViewModel に定義されたメソッドと結びつけることもできます。
そのほか、data-bind には class 属性を書き換える機能や、 繰り返しやテンプレートを使って DOM 構造の一部を書き換えるなどの様々な機能が標準で用意されています。さらに、自分で新しい機能をカスタムバインディングとして追加することもできます。この data-bind やカスタムバインディングについては次回以降に詳しく紹介します。
この宣言的バインディングを利用することで、DOM から対象の要素を取得して自分で値を書き換えたり、イベントハンドラを登録するといった従来であれば JavaScript のコードで表現する必要のあった物が一切必要なくなります。そのため、JavaScript のコードではアプリケーションが実現したいことの、本質的な部分を表現することに集中することができます。
ViewModel
ViewModel は、View に対して Model の持つデータやメソッドを適切な形に加工して公開したり、ユーザからの入力を Model に引き渡す役割を持ちます。また、UI を構築するためだけに必要な処理も ViewModel に置きます。
ViewModel は自身の情報が更新された場合に、View に対して更新を通知する必要があります。Knockout では Observables と呼ばれるオブジェクトを使用して値をラップすることでこれを実現することが出来るようになっています。Observables に関しても次回以降に詳しく紹介します。
View は ViewModel を映し出すものなので、当然ながら View に対して最低1つの ViewModel が必要になります。さらに、規模の大きめのアプリケーションであれば、一つの ViewModel を階層化した複数のモジュールに分割して実装するような場合もあります。
Model
Model と言う用語は様々な所で使われていますが、この MVVM の文脈で言う Model では、アプリケーションが取り組む問題領域に関するロジックや、サーバとの通信を用いた永続化処理など UI に直接依存しない物を表します。例えば、課題管理を行うようなアプリケーションであれば、登録されている課題のデータやバリデーション処理を持つオブジェクト、永続化処理などが Model に属します。Model のコードを UI に依存させないことで素直な JavaScript のコードとなり、UI に関する処理と入り混じったようなコードに比べてコードの理解やテストの作成が容易になります。
以上、Knockout の概要と MVVM パターンについての紹介でした。 次回は Knockout の基本機能について紹介する予定です。おたのしみに。