Vue.js で 複数のViewModelを連携させる
追記: 2016/04/28
1.xのVueでは、Reactのようにpropsを利用することでコンポーネント間で値の受け渡しを行うことができます。
また2.0では、$dispatch, $broadcastは非推奨になるので、注意してください。 refs: 2.0 features · vuejs/vue Wiki · GitHub
こんにちは。りんご と にんじん と 生姜の入ったジュースを飲んでいます、きたけーです。
今日はVue.js で 複数のViewModelの連携について考えてみます。 VueはViewModel間の親子関係を定義することができますが、今回考えるのは(DOMで)親子関係がなく「リストからひとつの項目を選択したときに、その項目の詳細を別の要素で表示する」ようなケースです。
べたに書くと、こんなかんじになります(Coffeeです)。
listVM = new Vue data: list: [] methods: selectItem: (e, index) -> detailVM.$data.item = @list[index] # ... detailVM = new Vue data: item: list[0] # ...
が、リストのVMが詳細のVMに依存していて(密結合)、テストを書くときに複数のViewModelを生成するのが面倒だし、メンテナンス性も下がりますね。
イベントで連携する
Vueでは、異なるViewModel間の連携をViewModelをcomponentという単位にして、イベントでおこなうことを勧めているっぽいです( http://vuejs.org/guide/composition.html の Event Communication Between Nested Components
)。
イベントでやりとりすることで疎結合にするのは、Vueに限らず、JSのコーディングでよくみられるやつですね。
component
componentは、Angular.jsのelement directiveのように汎用的に扱うために切り出したものと( http://vuejs.org/guide/composition.html のRegistering a Component
)、汎用的にするかは関係なく、ひとつのViewModelを複数の部分ViewModelに分割した場合の分割されたViewModelの両方を指すようです。後者の場合、ViewModelを生成するときのcomponentsオプションで指定することで、そのViewModel内だけでcomponentとして利用できます ( http://vuejs.org/guide/composition.html の Encapsulating Private Assets
)。
各ViewModelをcomponentにして、イベントでやりとりするように書き直すとこんなかんじです。
List = Vue.extend data: listData: [] methods: selectItem: (e, index) -> @$dispatch 'selectItem', @listData[index] # ... Detail = Vue.extend data: item: list[0] # ... appVM = new Vue components: list: List detail: Detail appVM.$on 'selectItem', (item) -> @$.detail.$data.item = item
ViewModel, componentのユニットテスト
componentのユニットテストを書くときは、new Detail()
のようにcomponentのオブジェクトを生成します。データを差し替えたかったらコンストラクタの引数でデータを渡すか(new Detail(data: {item: {}})
)、生成後に$data
を通して変更します。
記事を書いている途中でこの記事をみつけました。.Net(C#)の記事ですが、MVVMアーキテクチャパターンについての説明なので、Vueでも同じことがいえるはずです。書いたVueのコードを眺めながら、以下の記事の引用部分を読むと、ViewModelのユニットテストがDOMに依存しないことの認識が深まりました。
一般的にViewModelは、C#などの汎用プログラミング言語で記述され、プレゼンテーション・ロジックとステート(=状態)を持ちます。
...
ViewModelは、Viewへの参照を持ったり、Viewの特定の実装を意識したりしません。しかしViewModelはまったくViewを意識しないというわけでもないので注意が必要です。「ViewModelはViewを意識しますが、その実装について何も知らなくてもよいし、知るべきではない」という認識が妥当です。