はじめに
第3回では,
Vue.
Vue. jsのコンポーネント指向
Vue. jsのコンポーネント指向について
Vue.
大規模なアプリケーションを作成する際は,
基本的なcomponent
まず,
Vue.component('fruits-list-title', {
template: '<h1>フルーツ一覧</h1>'
})
この例では,<h1>フルーツ一覧</h1>
のHTML要素を含んだコンポーネントを,fruits-list-title
という名前で登録しています。登録したコンポーネントを別のコンポーネントから使用するには,
<div id="fruits-list">
<fruits-list-title></fruits-list-title>
</div>
このように構成した場合,
<div id="fruits-list">
<h1>フルーツ一覧</h1>
</div>
上記の例ではグローバルのVueにコンポーネントを,Vue.
の形式で追加していましたが,Vue.
を使用してコンポーネントを作成した上で,components
というoptionの中に以下のように登録してください。
var fruitsListChild = Vue.extend({
template: '<h1>フルーツ一覧</h1>'
})
var fruitsListParent = Vue.extend({
template: '<div>親コンポーネント<fruits-list-child></fruits-list-child></div>',
components: {
'fruits-list-child': fruitsListChild
}
})
new Vue({
el: "#fruits-list",
components: {
'fruits-list-parent': fruitsListParent
}
})
<div id="fruits-list">
<fruits-list-parent></fruits-list-parent>
</div>
jsfiddleで実行するとわかりますが,fruits-list-child
コンポーネントはfruits-list-parent
コンポーネントのスコープ内に定義されています。そのため,fruits-list-child
コンポーネントをfruits-list-parent
の外側で指定しても,
<div id="fruits-list">
<fruits-list-child></fruits-list-child>
<fruits-list-parent></fruits-list-parent>
</div>
コンポーネントのdataの扱い
各インスタンスごとに異なるdataオブジェクトを定義したいとき,
data: function(){
return {
fruits: [/* */]
}
}
コンポーネント間の通信
親コンポーネントと子コンポーネントのデータのやりとりを解説します。
親コンポーネントが子コンポーネントへデータを渡す際には,
例を見ていきましょう。以下のように,fruitsItems
に入ったフルーツの名前fruitsItem.
をリストするテンプレートを含んだコンポーネントを,fruits-list
という名前でVueインスタンスに登録しています。
Vue.component('fruits-list', {
props: ['fruitsItem'],
template: '<li>{{fruitsItem.name}}</li>'
});
配列fruitsは親コンポーネントのdataで定義します。
new Vue({
el: '#fruits-component',
data: {
fruitsItems: [
{name: '梨'},
{name: 'イチゴ'}
]
}
});
上記のように子コンポーネントのpropsオプションに変数名fruitsItems
を追加したうえで,fruits-list
タグの属性にfruits-items
を記述します。すると,
propsにキャメルケースでfruitsItems
と書いた場合,fruits-items
と書きます。
<div id="fruits-component">
<ol>
<fruits-list v-for="fruit in fruitsItems" fruits-item="fruit"></fruits-list>
</ol>
</div>
ここで,v-bind
ディレクティブを使用すると良いでしょう。
<fruits-list v-for="fruit in fruitsItems" v-bind:fruits-item="fruit"></fruits-list>
このように記述すると,fruits
の値が更新されるたびに,props
に書いたfruitsItems
が更新されます。なお,v-bind
は省略できます。
<fruits-list v-for="fruit in fruitsItems" :fruits-items="fruits"></fruits-list>
レンダリングされるHTML要素は以下のようになります。
<div id="fruits-component">
<ol>
<li>梨</li>
<li>イチゴ</li>
</ol>
</div>
ここまでのサンプルコードは,
子コンポーネントから親コンポーネントへの通信では,
- イベントのlisten:
$on(eventName)
- イベントのtrigger:
$emit(eventName)
※ $dispatchや$broadcastを紹介する記事を読んだことのある方もいるかもしれませんが,
こちらも例を見ていきましょう。以下のようにcounter-button
コンポーネントが定義されているとします。ボタンを押すとこのコンポーネントのaddToCart
メソッドが呼ばれ,increment
というカスタムイベントが発行されます。親コンポーネント側では v-on:increment(increment)
でincrement
イベントをlistenしているため,increment
メソッドが呼ばれます。
var counterButton = Vue.component( {
template: '<span>{{counter}}個<button v-on:click="addToCart">追加</button></span>',
data: function () {
return {
counter: 0
}
},
methods: {
addToCart: function () {
this.counter += 1
this.$emit('increment')
}
},
});
new Vue({
el: '#fruits-counter',
components:
'counter-button': counterButton
},
data: {
total: 0,
fruits: [
{name: '梨'},
{name: 'イチゴ'}
]
},
methods: {
increment: function () {
this.total += 1
}
}
});
<div id="fruits-counter">
<div v-for="fruit in fruits">
{{fruit.name}}: <counter-button v-on:increment="increment()"></counter-button>
</div>
<p>合計: {{total}}</p>
</div>
ここまでのサンプルコードは,
大規模なアプリケーションを作成していると,