【Vue.js】コンポーネントについて
はじめに
前回の「便利そうな仕組み」に引き続き、コンポーネントのまとめ。
メモレベルなので公式ドキュメントの確認も推奨。
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
コンポーネントの基本
コンポーネントは再利用可能な Vue インスタンス。
例: <button-counter> をルート Vue インスタンス内でカスタム要素として使用可能
code:index.js
Vue.component('button-counter',{
data:function(){ return { count:0 } },
template:'<button v-on="count++">You clicked me {{ count }} times.</button>'
})
new Vue({ el:'#components-demo'})
ポイント
- コンポーネントは data, computed, watch, methods, ライフサイクルフックを持てる
- 例外: el のようなルート専用オプション
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
コンポーネントの再利用
何度でも再利用可能。各インスタンスは独自の状態を保持
code:index.html
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
data は関数で定義
コンポーネントの data は関数で返す必要あり
code:index.js
data:function(){ return { count:0 } }
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
コンポーネントの編成
アプリ内ではコンポーネントはツリー状
- ヘッダー → タイトル / ナビゲーション
- コンテンツ → ブログ投稿など
- グローバル / ローカル登録が必要
code:index.js
Vue.component('my-component-name',{ /* ... */ })
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
プロパティ (props) で子コンポーネントにデータを渡す
code:index.js
Vue.component('blog-post',{ props:'title', template:'<h3>{{ title }}</h3>' })
code:index.html
<blog-post title="My journey with Vue"></blog-post>
- v-for で配列を使って複数投稿を描画可能
- 大きなコンポーネントは単一プロパティにまとめると整理しやすい
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
子コンポーネントの制御・イベント送出
- 親コンポーネントと連携して状態を操作可能
- $emit でイベントを送出
code:index.js
<button v-on:click="$emit('enlarge-text',0.1)">Enlarge text</button>
- 親で受け取り、値を反映
code:index.html
<blog-post v-on:enlarge-text="postFontSize += $event"></blog-post>
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
v-model のカスタムコンポーネント対応
code:index.js
Vue.component('custom-input',{
props:'value',
template:<input v-bind:value="value" v-on:input="$emit('input',$event.target.value)">
})
code:index.html
<custom-input v-model="searchText"></custom-input>
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
スロットでコンテンツを挿入
code:index.js
Vue.component('alert-box',{ template:<div><strong>Error!</strong><slot></slot></div> })
code:index.html
<alert-box>Something bad happened.</alert-box>
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
動的コンポーネント
code:index.html
<component v-bind:is="currentTabComponent"></component>
- currentTabComponent にコンポーネント名またはオプションオブジェクトを指定
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
DOMテンプレート制限
<ul>, <ol>, <table>, <select> 内では <li>, <tr>, <option> 以外は無効
- 回避: is 属性を使用
code:index.html
<table><tr is="blog-post-row"></tr></table>
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
コンポーネントの登録
ローカル登録
code:index.js
new Vue({
el:'#app',
components:{ 'component-a':ComponentA, 'component-b':ComponentB }
})
- ローカル登録コンポーネントは他のサブコンポーネントで使用不可
→ ComponentB 内で ComponentA を使う場合は ComponentB 内で再登録
------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ ------------------ --------------
まとめ
- Vue コンポーネントは再利用可能な Vue インスタンス
- props, v-model, スロット, 動的コンポーネントで柔軟に扱える
- DOM 制限に注意し、グローバル/ローカル登録を理解して整理する