ViewModelの定義
VMインスタンスの生成
Vue.jsでは、Vueコンストラクタをnewして生成されるVM(ViewModel)インスタンスがコアとなる要素です。まずは、以下の簡単なサンプルを紹介します。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="http://vuejs.org/js/vue.min.js"></script> </head> <body> <div id="app"> <input type="text" v-model="message"> <div>{{message}}</div> </div> <script> // vmインスタンスの初期化 var vm = new Vue({ el: '#app', data: { message: "" } }); </script> </body> </html>
上記のHTMLを保存してブラウザで開くと、inputに何か値を入力すると同時にその値が下に表示されます。
この例で実装時に開発者が意識して行うステップは以下の3点です。
- 入力用のViewの定義:Inputタグ内で、ViewとModelを同期させるためのv-model(ディレクティブ)にmessageプロパティを指定する
- 出力用のViewの定義:messageの出力用にHTML内に{{message}}を記述する
- Modelの定義:関連付けるDOMエレメントをelに、データバインディング対象のプロパティmessageをdataに指定してVMインスタンスを生成する
ステップ3のVueコンストラクタをnewしてVMインスタンスを生成すると、内部的にコンパイルと呼ばれる処理が実行され、ViewとModelが双方向にバインディングされます。この双方向バインディングにより、インタラクティブな振る舞いをイベント処理などのコードを一切記述することなく実現できます。
Vue.jsではVMインスタンス初期化時にコンパイルと呼ばれる仕組みが実行されます。
コンパイルの前準備として、初期化時にdataで指定したプロパティは列挙可能(enumerable)な各プロパティに対してECMAScript 5のgetter/setterを追加します。コンパイルでは、elで指定されたDOMエレメント自身とその子孫要素を辿り、Vue.jsが付与したgetter/setterを利用してModelとViewの同期処理が可能な状態に変換されます。
本章では、elやdataを代表としたVMインスタンス初期化時のオプションについて解説します(すべての初期化時のオプションについてはOptionsのページを参考にしてください)。
el
elはVMインスタンスのバインディング対象となるDOMエレメントを指定するオプションです。elにはセレクタによる指定やHTMLノードによる指定ができます(現時点では、セレクタによる複数ノードの指定は対応していません)。
var vm = new Vue({ el: "#app" }); // インスタンス生成後には$elでアクセス可能 vm.$el;
VMインスタンスに関連付けられたDOMエレメント配下でのバインディングには、Mustache記法を使用することができます。
var vm = new Vue({ el: "#app", data: { text: "通常のテキスト", unescapedText: "<div>HTMLを有効化して<br>表示したい時のテキスト</div>", onetimeText: "一度だけバインディングされる文字列" } });
<div id="app"> <!-- htmlエスケープされる通常の出力 v-textディレクティブと等価--> {{text}} <!-- htmlエスケープされない出力 v-htmlディレクティブと等価 --> {{{unescapedText}}} <!-- 一度だけのバインディング --> {{* onetimeText}} </div>
関連付けられたDOMは自身のmethodsの中でthis.$elとしてアクセスできます(Vue.jsでは基本的にVMインスタンス自身のプロパティおよびメソッドは$接頭辞が付きます)。
ただし、DOM操作のコードを直接記述することは、ViewModelの定義によりDOMを意識させない仕組みを提供するMVVMの思想と反します。DOM操作が必要な場合はカスタムディレクティブを使うと良いでしょう。
data
dataはMVVMにおけるModelの部分を担うオプションです。dataで指定したオブジェクトは初期化後にvm.$dataとしてアクセス可能です。また、dataオブジェクトはVMインスタンス自身のプロパティとしても同期されます。
var data = { a: 1 }; var vm = new Vue({ data: data }); vm.$data === data; // -> true // VMインスタンス自身のプロパティとしてアクセスできる vm.a; // -> 1
dataで指定するオブジェクトに対するバインディングのための改変(getter/setterの付与)はVMインスタンス初期化時に行われます。そのため、後から$dataにプロパティを追加した場合、双方向バインディングされない点に注意が必要です。途中からdataにバインディングの対象を追加・削除したい場合は$add, $deleteを使います。
// vm.$data.bを追加 vm.$add("b", {value: "hoge"}); // vm.$data.bを削除 vm.$delete("b");
dataに指定した列挙可能(enumerable)なプロパティがバインディングの対象になりますが、「$」か「_」で始まるプロパティに関してはgetter/setterの付与がスキップされます。
methods
methodsオプションで指定したfunctionはVMインスタンス自身のfunctionとしてミックスインされます。定義したfunctionの実行時のthisのコンテキストはVMインスタンス自身になります。
var vm = new Vue({ data: { a: 1 }, methods: { plus: function () { // thisのcontextはvmインスタンス自身になる this.a++; } } }); // vmインスタンスから直接呼ぶことができる vm.plus(); vm.a; // 2
上記の例はvmインスタンスから直接呼び出す例です。他にも後述のディレクティブの項で紹介するv-onを用いてmethodsで定義したfunctionを呼び出すこともできます。
computed
computedオプションはカスタムのgetter/setterを定義することができる仕組みです。指定したプロパティはVMインスタンスにミックスインされます。また、指定したgetter/setterのthisのコンテキストはVMインスタンス自身になります。
var vm = new Vue({ data: { a: 1 }, computed: { // function1つのみの定義の場合はgetterとして動作する aDouble: function () { return this.a * 2; }, // getterとsetter両方を指定 aPlus: { get: function () { return this.a + 1; }, set: function (v) { this.a = v - 1; } } } }); vm.aPlus; // getterが呼ばれる -> 2 vm.aPlus = 3; // setterが呼ばれる vm.a; // -> 2 vm.aDouble; // -> 4
ライフサイクル
VMインスタンスのライフサイクルの各メソッドを生成時のオプションとして指定できます(v0.11より前のバージョンではcreatedやreadyなどタイミングがv0.11と異なるので注意が必要です)。
ライフサイクル | 説明 |
---|---|
created | DOMのコンパイル以外(dataの監視の仕組みなど)がすべて終わったタイミングで呼ばれる |
beforeCompile | コンパイルが始まる直前に呼ばれる |
compiled | コンパイルが終わり双方向バインディングが準備された状態で呼ばれる($elがDOMに挿入されていることは保証されていない) |
ready | コンパイルが終わり初めて$elがDOMに挿入された時に呼ばれる |
attached | ディレクティブや$appendToなどにより$elがDOMに挿入された時に呼ばれる |
detached | ディレクティブや$removeなどにより$elがDOMから取り除かれた時に呼ばれる |
beforeDestroy | $destroyが呼ばれる直前に呼ばれる(vmインスタンスが正しく動作する) |
destroyed | $destroyが呼ばれ、バインディングなどがすべてはずされ、子孫要素のvmインスタンスも破棄された時点で呼ばれる |
var vm = new Vue({ el: "#app", data: { a: 1 }, created: function(){ this.a++; // DOMに挿入される前の処理 this.$el; // -> null, this.$elがまだセットされていない }, ready: function(){ this.$el.parentNode; // DOMに挿入された後なので、$elや親ノードにアクセスできる } });
その他のVMインスタンス初期化時のオプション
これまで紹介した代表的なVMインスタンス初期化時のオプション以外にも、例えば、watchなど多数のオプションが存在します。watchは指定したプロパティに対して変更監視のコールバックを登録するオプションです。
var vm = new Vue({ data: { a: 1 }, watch: { 'a': function (newVal, oldVal) { console.log('new: ' + newVal + ', oldVal: ' + oldVal); } } }); vm.a = 2 // -> new: 2, old: 1
初期化時のオプションと同様に、$接頭辞から始まるVMインスタンス自身のプロパティやメソッドもさまざまなものが提供されています。例えば、上記で紹介したオプションwatchの内部ではインスタンスメソッドである$watchが使用されています。本稿では解説しませんが、興味のある方はインスタンスメソッドのページをご参照ください。