Vue.js

Vue.js コンポーネントを定義する方法

こんにちは!ともです(@_tomo_engineer)!

今回はVue.jsのコンポーネントを定義する方法について見ていきます。

参考にしたものは以下です。

基礎から学ぶVue.js(書籍)

Vue.js:日本語ドキュメント

コンポーネントとは

コンポーネントとは日本語で『構成要素』という意味である様に、Webアプリケーションの画面を構成する部品を表しています。

画面を作っていると、

あそこでも同じ様なHTML書いたな、コピペしよう!

っていう場合があると思うんですが、そのコピペしよう!、とした部分はWebアプリケーションを構成している部品と考えれるのです。

猫本には次の様に書かれていました。

コンポーネントとは、UI部品、簡単にいえば機能を持つことのできるHTML要素の設計図です。外見だけでなく、どんなプロパティを持って、どんなアクションをするかを細かく定義できます。

引用元:基礎から学ぶVue.js(書籍)

HTMLのコピペとは違い、管理しやすい様にVue.jsではUI部品を『コンポーネント』という単位で管理します。

HTMLのコピペもコンポーネントも『再利用』を目的としています。

あるUI部品をHTMLのコピペで100個作成したとして、このUI部品全てに共通する修正を行わなければならない場合、途方も無い作業となる事は言うまでもありません。

Vue.jsのコンポーネントと言う単位でUI部品を管理すると、この悩みから解消されるのです。

コンポーネントを定義する

コンポーネントはグローバルまたはローカルに登録し、カスタムタグとして利用する事ができます。

グローバルに登録

次の様にVue.componentメソッドを使ってグローバルに登録する事で、全てのコンポーネントから利用できます。

次の例では『my-component』というcomponentを定義しました。

Vue.component('my-component', {
    template: '<p>My Component</p>'
})

そして登録したコンポーネントを利用してみます。

<div id="app">
        <my-component></my-component>
</div>

これはつまり、

<div id="app">
        <p>My Component</p>
</div>

という描画になり、部品の再利用を行えます。

ローカルに登録する

ローカルとしてコンポーネントを登録するにはcomponentsオプションを利用します。

// コンポーネントを定義
var myComponent = {
    template: '<p>MyLocalComponent</p>'
}

new Vue({
    el: '#app',
    components: {// ローカルに登録
        'my-component' : myComponent
    }
})

この様にコンポーネント(myComponent)を定義しておき、名前(my-component)を付けてローカルに登録しています。

コンポーネントの命名規則は『ハイフンを1つ以上含むケバブケース』なのでmyComponentの様なキャメルケースは利用できません。

コンポーネントのオプション

new Vue()と同じ様に、コンポーネント内ではdataやmethodsを定義する事ができます。ローカルに登録する例の場合だと次の様に書きます。

var myComponent = {
    template: '<p>{{message}}</p>',
    data: function(){ // データを返す関数にする
        return {
            message: 'Hello Vue.js'
        }
    },
    methods: { // メソッド・ウォッチャなども定義できる

    }
}

ルートコンストラクタと同じ様にdataやmethodsを定義する事ができます。

しかし注意する点としてはdataはオブジェクトを返す関数にする必要があるという事です。

data: {
   message: 'Hello Vue.js'
 }

これまで学習して来た時のdataオプションの定義方法は上記でした。componentとは区別する必要があります。

もしcomponentにも関わらず、オブジェクトを返す関数として定義せず、コンストラクタで行う方法でdataを定義した場合次の様なエラーが発生します。

The “data” option should be a function that returns a per-instance value in component definitions.

component内のデータは関数として定義し、returnする必要があることに注意しなければなりません。この理由については猫本に次の様に書かれていました。

これは、複数のコンポーネントインスタンス間で同じオブジェクトを参照して状態が共有されてしまうのを回避するためです。

引用元:基礎から学ぶVue.js(書籍)

componentは『再利用』することを目的としているので、1つの画面で同じ部品(コンポーネント)が複数登場しえます。

<my-component></my-component> => <input type="text" v-model="message"> // インスタンス1
 <my-component></my-component> => <input type="text" v-model="message"> // インスタンス2

この様に2度使用したとき、dataを区別して扱う必要があります。

同じvalueであっても、インスタンス1のmessageインスタンス2のmessageと区別する必要があります。そのために関数として定義しreturnする必要があります。

ルート要素は単一でなければならない

テンプレートは全体を何かしらのタグで囲まれている必要があります。

// divで囲まれている(OK)
template: '<div><input type="text" v-model="message">{{message}}</div>',

// 何にも囲まれていない(NO)
// {{message}}部分が無視される
template: '<input type="text" v-model="message">{{message}}',

この様にテンプレートは囲う必要があり、はみ出た部分は無視されます。エラーも以下の様に出ます。

[Vue warn]: Error compiling template:

<input type=”text” v-model=”message”>{{message}}

– text “{{message}}” outside root element will be ignored.

templateオプションで定義

最も基本的な定義方法がtemplateオプションで定義する方法です。

Vue.component({
     template: '<p>テンプレート</p>'
});

またES2015から利用できるようになった、テンプレートリテラルの文法を利用して次のように書くこともできます。

Vue.component({
   template: `<div>
      <p>テンプレート<p>
      <p>テンプレート<p>
   </div>`
});

複数の行にまたがる場合はテンプレートリテラルの記法で書いた方が分かりやすいです。

text/x-template+セレクタ

scriptにtext/x-templateを付ける事でブラウザにDOMと認識されずに定義する事ができます。

<script text/x-template id="child-template">
   <p>テンプレート</p>
</script>

x-templateで定義したテンプレートを、idを指定してコンポーネントのテンプレートオプションに設定する事ができます。

Vue.component('my-component', {
   template: '#child-template'
})

まとめ

今回はコンポーネントの定義の方法について書きました。

まとめは以下です。

まとめ
  • コンポーネントとはUI部品である
  • グローバルに登録する場合は、componentメソッド
  • ローカルに登録する場合は、componentsオプション
  • templateの名前はケバブケース
  • componentのdataオプションは関数として登録しreturnでデータを返す必要がある

コンポーネントはVue.jsで一番重要なところだと感じているので丁寧に学習を進めて行きたいです。