単一ファイルコンポーネントとは?
VueCLIでプロジェクトを作成するとsrc\components\HelloWorld.vue
というファイルが生成されます。このような拡張子がvueのファイルを単一ファイルコンポーネントといいます。
その名の通り、1つのvueファイルが1つのコンポーネントとして定義されます。
ちなみにCDN読み込みでもコンポーネントを作成することはできますが、単一ファイルコンポーネントを利用したほうが開発しやすいためここでは割愛します。
単一ファイルコンポーネントは、HTMLにより見た目を構成するtemplate、データ定義や処理を定義するscript、スタイルを定義するstyleの3つで構成されます。
<template> <!-- ここにhtmlを記載 --> </template> <script> //ここにデータ定義や処理を記載 </script> <style> //ここにスタイルを記載 </style>
簡単ではありますが以下のようなボタンコンポーネントを元に解説していきます。 MyButton.vueが実際に作ったボタンコンポーネントで、App.vueで使用しています。
template
templateタグ内にはHTMLにより見た目の宣言していきます。
注意点として、親となる要素が一つになるように宣言する必要があります。例えば次の様なケースはエラーになります。
<template> <h1>Title</h1> <h2>SubTitle</h2> </template>
正しく動作させるためには以下のように親要素を追加する必要があります。
<template> <div> <h1>Title</h1> <h2>SubTitle</h2> </div> </template>
今回のボタンの場合は、button要素1つだけで構成しています。データバインドやイベントハンドリングを行っていますが解説は後述します。
slot
MyButton.vueでは、<slot />
というタグをbutton要素で囲んでいます。そしてApp.vueでは以下のようにMyButtonコンポーネントを使用しています。
<my-button>Default</my-button>
これをDOMに展開すると以下のようになります。
<button>Default</button>
このようにslotには、コンポーネントで囲んだ要素が展開されます。
script
scriptタグ内には主にVueに関する記述を行っていきます。基本的にはexport default
にVueのオプションオブジェクトを記載していきます。
computedやmethodsなど基本的には同じように宣言できます。定義された内容は単一ファイルコンポーネント内でのみ有効になります。
data
コンポーネントではdataの宣言方法が以下のようにメソッドになります。
export default { data() { return { //ここにデータ宣言 } } }
dataをメソッドとして宣言する理由として、公式ドキュメントに以下のように記載されています。
基本的な例では、data は直接プレーンなオブジェクトとして宣言しています。これは、new Vue() によって単一のインスタンスだけが作成されるためです。しかしながら、コンポーネントを定義するときは、data は初期データオブジェクトを返す関数として宣言されなければなりません。なぜでしょうか?同じ定義を使用して作成された多くのインスタンスがあるからです。まだ data に対してプレーンなオブジェクトを使用している場合、同じオブジェクトが作成された全てのインスタンス全体を横断して参照によって共有されます!data 関数を提供することによって、新しいインスタンスが作成される度に、単にそれは初期データの新しいコピーを返すための関数として呼び出すことができます。
宣言方法以外に変わりはなく、データ参照などはそのまま行えます。
props
propsはコンポーネントのプロパティを意味します。プロパティは属性として値を設定することができ、データと同じように値を参照することができます。
例えばMyButton.vueではプロパティとしてtypeとsizeを以下のように宣言しています。
export default { props: { type: { type: String, default: '' }, size: { type: String, default: '' } } }
さらにtemplateでは以下のようにプロパティをクラスバインディングしています。
<button class="my-button" :class="[type, size]"><slot /></button>
そしてApp.vueでは次のようにMyButtonコンポーネントを使用しています。
<my-button>Default</my-button> <my-button type="primary">Primary</my-button> <my-button size="small">Small</my-button>
これをDOMに展開すると以下のようになり、クラスによりそれぞれ見た目が違うボタンが生成されます。
<button class="my-button">Default</button> <button class="my-button primary">Primary</button> <button class="my-button small">Small</button>
このようにプロパティは親(呼び出し元)からのデータ(値)の受け口となり、受け取った値を基に処理を行う場合に使用します。
ただし、以下のように受け取ったプロパティの値を変更することはできません。
this.type = "error"
$emit()
MyButton.vueでは以下のようにbutton要素にイベントハンドリングが宣言されています。
<button @click="click"><slot /></button>
export default { methods: { click() { this.$emit('myclick'); } } }
ボタンをクリックするとclickメソッドが実行されるため、結果的にthis.$emit('myclick')
が実行されます。このthis.$emit('myclick')
の意味を解説すると、「myclickイベントとしてハンドリングされた処理を実行する」ということになります。
ではApp.vueを見てみましょう。 App.vueでは次のようにmyclickイベントとしてclickメソッドを宣言しています。
<my-button @myclick="click">Click Me!</my-button>
export default { data() { return { count: 0 } }, methods: { click() { this.count++; } } }
これによりボタンをクリックすると次のような流れでイベントが発生していき、最終的にApp.vueのclickメソッドが実行されます。
- (MyButton.vue) buttonタグのclickイベント
- (MyButton.vue) clickメソッド
- (App.vue) my-buttonタグのmyclickイベント
- (App.vue) clickメソッド
このように$emit()を利用することで、親からイベントとして処理を受け取り、コンポーネント内で実行することができます。
まとめ
Vue CLIプロジェクトにおいてコンポーネントを作らないプロジェクトはまずないでしょう。 まずは今回のボタンのように小さな単位で作成し、徐々に複雑なものを作成していくのがおすすめです。
今回の記事では説明しきれていない部分が多々あるためまた別記事で紹介したいと思います。
- Vue.jsのおすすめ書籍はコチラ -
コメント