Vue.js コンポーネント
前回の記事はこちら
Vue.js フォーム入力バインディング
コンポーネントとは
ページを構成するUI部品で再利用可能なインスタンスです。
HTMLベースのテンプレートとjavascriptで書かれたロジックで構成されます。
コンポーネント使うメリットは以下です。
①再利用ができる
②メンテナンス性が高まる
グローバル登録
Helloと出力するコンポーネントを作成し複数回利用します。
jsfiddleで実際に記述しながら読むことをおすすめします。
<divid="app"><hello-component></hello-component><hello-component></hello-component><hello-component></hello-component></div><script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
Vue.component('hello-component',{template:'<p>Hello</p>'})varapp=newVue({el:'#app',})
コンポーネントの記述は第1引数にコンポーネント名を第2引数に処理内容を記述しましょう。
グローバル登録されたコンポーネントはすべてのVueインスタンスから利用可能です。
ローカル登録
特定のVueインスタンス配下でのみ利用するコンポーネントは
ローカル登録によってスコープ(範囲)を狭めることができます。
さきほどグローバル登録したコンポーネントをローカル登録に変更します。
<divid="app"><hello-component></hello-component><hello-component></hello-component><hello-component></hello-component></div><script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
varhelloComponent={template:"<p>Hello</p>"}varapp=newVue({el:'#app',components:{'hello-component':helloComponent}})
まず使用するVueインスタンスよりも先にコンポーネントを定義します。
次にvueインスタンス内のコンポーネントオプションにプロパティとして設定しましょう。
コンポーネント名
コンポーネント名を登録する際はハイフンを1つ以上含む(ケバブケース)必要があります。
例)
・hello-component OK
・button-counter OK
・hello NG
・helloComponent NG キャメルケースのためNG
理由は既に存在するHTMLや将来定義されるHTML要素との衝突を避けるためです。
ただしVue.jsのスタイルガイドではパスカル記法(全ての単語の先頭が大文字)を
推奨していますので状況に応じて混在しないように使い分けることをおすすめします。
Vue.jsスタイルガイド
<!--NG記述です--><divid="app"><hello></hello><hello></hello><hello></hello></div><script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
//NG記述ですvarhelloComponent={template:"<p>Hello</p>"}varapp=newVue({el:'#app',components:{'hello':helloComponent}})
※実行結果として動作しますが、仮に将来helloというタグがHTMLで定義された場合は衝突します。
コンポーネントのオプション
ボタンを押すとクリック数をカウントするコードをコンポーネントで記述しましょう。
<divid="app"><button-counter></button-counter><button-counter></button-counter><button-counter></button-counter></div><script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
Vue.component('button-counter',{data:function(){return{count:0}},template:'<button v-on:click="count++">{{ count }}</button>'})varapp=newVue({el:'#app'})
それぞれのボタンはカウント数を独自に保持しています。
これはコンポーネントを作成するたびに新しいインスタンスが作成されるためです。
コンポーネントのdataは直接定義されず関数となる必要があります。
//例 直接定義data:{count:0}//例 関数定義data:function(){return{count:0}}
理由は各インスタンスが独自にオブジェクトを利用できるようにするためです。
またテンプレートのルート要素は単一である必要があります。
上記のカウンターに"count:"のラベルをつけてみましょう。
<divid="app"><button-counter></button-counter><button-counter></button-counter><button-counter></button-counter></div><script src ="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
Vue.component('button-counter',{data:function(){return{count:0}},template:'<span>count:</span><button v-on:click="count++">{{ count }}</button>'})varapp=newVue({el:'#app'})
上記の記述ではspanとbuttonで要素が複数になっているためコンパイルエラーが発生します。
この場合はdivタグなどで囲んで要素を1つにまとめる必要があります。
//テンプレートを修正Vue.component('button-counter',{data:function(){return{count:0}},template:'<div><span>count : </span><button v-on:click="count++">{{ count }}</button></div>'//divで囲んで単数化})varapp=newVue({el:'#app'})
コンポーネント間の通信
複数のコンポーネントを並列または入れ子に配置された場合
スコープ(データの有効範囲)という概念が発生します。
コンポーネントで定義された情報(データ、メソッドなど)に
アクセスできるのはそのコンポーネントだけということになります。
次回はトランジションです。
Vue.js トランジション