[Knockout.js基本編]最低限の構成で「Hello World」してみる

2014年03月10日

カテゴリー:

前回はKnockout.jsの概要について書きましたが、今回はKnockout.jsの基本的な使い方の紹介と簡単なサンプルの作成をしてみます。

Knockout.jsの使い方

Knockout.jsは1つのJavaScriptファイルで作成されており、これをサイトに読み込むだけで準備完了です。他に必要なものはありません。Knockout.jsのファイルは下記の本家サイトからダウンロードできます。

Knockout : Home

Knockout_home 上記のサイトにダウンロードボタンがありますので、そちらからJavaScriptファイルをダウンロードしてください。
また、ダウンロードではなく、CDN上のソースファイルを直接参照して読み込む場合は、下記のURLが公開されています。

Microsoft Ajax CDN

http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js

CDNJS

http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js

最低限の構成で「Hello World」

Knockout.jsを活用する場合、最低限、以下に示す構成要素が必要です。

  • Knockout.js本体の読み込み
  • View(HTMLテンプレート)の定義
  • ViewModel(Viewの状態とViewから呼び出されるイベントハンドラを格納するJavaScriptオブジェクト)の定義
  • ViewとViewModelの関連付け

※Knockout.jsはMVVM(Model-View-ViewModel)パターンをサポートするJavaScriptフレームワークですが、このフレームワークに関係があるのはこの内ViewとViewModel部分だけです。Model部分についてはKnockout.jsでは関知しませんので、必要に応じてアプリケーション側で用意します。

上記の最低限の構成要素を踏まえ、まずはごくシンプルなサンプルコードとして、画面に「Hello World!」と表示させるためのコードを次に示します。

<html>
  <body>
    <span data-bind="text: sampleText"></span>
    <script src="knockout-2.2.1.js"></script>
    <script>
    window.onload = function () {
        var viewModel = {
                sampleText: 'Hello World!'
            };

        ko.applyBindings(viewModel);
    };
    </script>
  </body>
</html>

※本来であれば5~13行目は外部ファイル化すべきところですが、とりあえずコードのボリュームが一目で分かるようにしたかったので、ご容赦下さい。

では、このコードでポイントとなる部分を順に解説していきます。

Knockout.js本体の読み込み

コードの4行目でKnockout.jsの本体を読み込んでいます。当たり前ですがこれが無いと始まりませんね。
この例ではbodyタグの中で読み込みを行っていますが、headタグの中で読み込んでも問題ありません。

View(HTMLテンプレート)の定義

コードの3行目ではHTMLテンプレートの定義をしています。MVVMパターンにおける「View」の定義部分です。といっても、このサンプルではたった1行のテンプレートですが、実際にはもっと沢山のタグの組み合わせで構成されることになると思います。

「data-bind="text: sampleText"」の部分ですが、Knockout.jsでは基本的にHTML要素のdata-bind属性にその要素の振る舞いと値を「data-bind="(振る舞い):(値)"」という形式で書いていくことになります。

この「振る舞い」は「バインディング」と呼ばれ、Knockout.jsには様々なバインディングが用意されています。
また、値はバインディングに渡すパラメータの様なもので、実際にはオブジェクトのプロパティや、式などが入ります。

この例ではtextバインディングが使用されています。textバインディングは対象となる要素(ここではspan)に対し、値として渡された文字列を設定します。
ここでは値として「sampleText」と書かれていますが、これは次に解説するViewModelオブジェクトのsampleTextプロパティを指します。つまり、sampleTextプロパティに設定された値がこの要素のテキストとして表示されることになります。

ViewModelオブジェクトの定義

7~9行目の部分ではViewModelオブジェクトの定義をしています。ViewModelオブジェクトはMVVMパターンにおけるViewModel部分であり、Viewの状態やViewから呼び出されるイベントハンドラを格納します。

今回の例では、sampleTextというプロパティに「Hello World!」という文字列をセットしていますが、これは3行目のspanタグのtextバインディングによって読みだされます。


また、今回の例ではViewModelオブジェクトの定義をオブジェクトリテラル表記で行い、オブジェクトの定義と作成を同時に行っていますが、下記の例の様にコンストラクタ関数を使って定義し、後でnewを使ってオブジェクトを作成するやり方も良く見かけます。どちらのやり方でも良いと思います。

<html>
  <body>
    <span data-bind="text: sampleText"></span>
    <script src="knockout-2.2.1.js"></script>
    <script>
    window.onload = function () {
        var ViewModel = function () {
                this.sampleText = 'Hello World!';
            };

        ko.applyBindings(new ViewModel());
    };
    </script>
  </body>
</html>



ViewとViewModelの関連付け

ここまでの段階で、HTMLテンプレートとViewModelオブジェクトの定義は完了しましたが、これだけでは動きません。 この時点ではViewとViewModelがそれぞれ独立して存在しているだけなので、最後のアクションとしてViewとViewModelとの関連づけを行う必要があります。この関連付けを行っているのが、11行目の「ko.applyBindings(viewModel);」の部分です。

ここで出てくる「ko」は、Knockout.js本体側で定義されているグローバル変数で、Knockout.js本体を読み込むことで使用できるようになります。このオブジェクトにはKnockout.jsで利用できる全てのメソッドが格納されています。

applyBindingsメソッドはViewとViewModelオブジェクトを関連付けるメソッドで、Knockout.jsのもっとも基本的なメソッドです。Knockout.jsを利用する場合、おそらく必ず呼び出されるメソッドだと思います。

applyBindingsメソッドの第1引数にはViewModelオブジェクトを指定します。今回のサンプルでは省略されていますが、第2引数を指定することも可能です。

第1引数のみを指定した場合には、全DOM要素(HTML全体)に対してViewModelオブジェクトが関連付けされます。言葉を変えると、HTMLのどの要素からでもViewModelオブジェクトを参照することができる、ということです。
第2引数にはDOM要素を指定することが可能で、この場合引数として指定されたDOM要素以下にのみViewModelオブジェクトを関連づけることができます。

例)
ko.applyBindings(viewModel, document.getElementById(‘someElementId’));
ko.applyBindings(viewModel, jQuery(‘#someElementId’));

上記の例だと、someElementIdというIDが付けられた要素、およびその要素の配下の要素からでしかViewModelオブジェクトを参照することができなくなります。Viewをいくつかの領域に分割して、それぞれに個別のViewModelオブジェクトを関連付けたいようなケースでは第2引数を指定すると良いでしょう。

注意しなければならないことは、applyBindings関数を正常に動作させるにはDOMが準備されている必要があるということです。

今回のサンプルでは、applyBindingsメソッドの呼び出しがwindow.onloadイベントの中で行われているので、DOMが準備出来てから呼び出しを行っているため問題ありませんが、下記のコード例ではDOMの準備が完了する前にapplyBindings関数が呼び出されてしまうので、うまく動作しません。(ブラウザのコンソールウィンドウには「Cannot read property ‘nodeType’ of null」というエラーメッセージが出ます。)

<html>
  <head>
    <script src="knockout-2.2.1.js"></script>
    <script>
    var viewModel = {
            sampleText: 'Hello World!'
        };

    ko.applyBindings(viewModel);
    </script>
  </head>
  <body>
    <span data-bind="text: sampleText"></span>
  </body>
</html>

ko.applyBindingsメソッドを呼び出す場合、素のブラウザJavaScriptであればonload時、jQueryであればjQuery関数に指定するコールバック関数の中で呼び出すようにすれば、このようなエラーを未然に防ぐことができます。

▼applyBindings関数についてはこちらが参考になります。
Knockout.js/applyBindings関数

まとめ

今回のコードでも分かるように、Kockout.jsを利用するとJavaScriptコードの中でDOMを操作する必要がなくなります。DOMではなく、ViewModelオブジェクトが操作の対象になるからです。
View(HTMLテンプレート)とViewModelオブジェクトとの関連付け(データバインド)はKnockout.jsのapplyBindingsメソッドを呼び出すだけです。

従来はjQueryを使ってJavaScript側でDOMの書き換えを行っていたようなケースでも、Knockout.jsを利用すればJavaScriptコードからDOM操作をするためのコードを排除することができます。そのため、容易にHTMLとJavaScriptとの分離を行うことができます。これはひとえにKnockout.jsが提供するデータバインド機構の恩恵だと言えるでしょう。


さて、今回はKnockout.jsのごく基本的なサンプルをもとにViewやViewModelの定義、ViewとViewModelの関連付けといった、Knockout.jsを利用する上での最も基本的な事項について解説しました。

これだけでもKnockout.jsを使うメリットがあるとは思いますが、まだまだKnockout.jsの便利さの半分くらいしか紹介出来ていません。

今回のサンプルではViewModelオブジェクトのプロパティの内容をHTMLテンプレートに表示させるだけのものでした。しかし、このままではHTMLテンプレートへの表示が終わった後に、プロパティの内容が変更してもHTMLテンプレートにはその変更内容が反映されません。

次回はViewModelオブジェクトの変更を自動的にHTMLテンプレートに反映させるための「Observable(=オブザーバブル)」という機構について解説したいと思います。Observableはデータバインドと同様、Knockout.jsにおける基本であり重要なポイントです。

おまけ:インタラクティブ・チュートリアルについて

knockout_tutorial.jpg

本家サイトにはKnockout.jsの学習に役立つ「インタラクティブ・チュートリアル」というものが用意されています。

これは、ブラウザ上でView(HTML)とViewModel(JavaScript)のコードを入力するだけで、簡単に動作確認をすることができるツールですので、私もバインディングの動作確認などに利用しています。
また、チュートリアル形式で徐々にステップアップしながら学習することもできるので、Knockout.jsを基礎を理解するのに非常に役に立つと思います。

▼インタラクティブ・チュートリアル(※本家サイト:英語)
http://learn.knockoutjs.com/