はじめに
第3回では、Vue.jsのコンポーネントの基本的な作成の仕方と使用方法を紹介します。
Vue.jsは、UIをコンポーネント化する仕組みを持っています。HTML+CSS+JavaSciptで構築されたUIの再利用性が高まり、カプセル化されて開発で意識すべき範囲を限定できるようになります。今回の記事が、プロジェクトにVue.jsを導入する際のコンポーネント設計のイメージをつかむ助けになれば幸いです。
Vue.jsのコンポーネント指向
Vue.jsのコンポーネント指向について
Vue.jsのコンポーネントは、大まかにWeb ComponentのCustom Elementsの仕様に沿って設計されています。コンポーネントは、定義したタグ名で親となるコンポーネントのHTML上に記述できます。
大規模なアプリケーションを作成する際は、コンポーネントをツリー状に構成してわかりやすく設計することが可能です。
基本的なcomponent
まず、基本的なVue.jsのコンポーネントの書き方を示します。
この例では、<h1>フルーツ一覧</h1>
のHTML要素を含んだコンポーネントを、fruits-list-title
という名前で登録しています。登録したコンポーネントを別のコンポーネントから使用するには、以下のように親となるコンポーネントの中にHTMLタグを書きます。
このように構成した場合、実際にレンダリングされるHTML要素は、以下のようになります。
上記の例ではグローバルのVueにコンポーネントを、Vue.component(tag, constructor)
の形式で追加していましたが、ある特定のVueコンポーネントの中でのみ使えるように子コンポーネントを登録することもできます。Vue.extend()
を使用してコンポーネントを作成した上で、親となるコンポーネントのcomponents
というoptionの中に以下のように登録してください。
jsfiddleで実行するとわかりますが、fruits-list-child
コンポーネントはfruits-list-parent
コンポーネントのスコープ内に定義されています。そのため、以下のHTMLファイルのようにfruits-list-child
コンポーネントをfruits-list-parent
の外側で指定しても、実行されません。
コンポーネントのdataの扱い
各インスタンスごとに異なるdataオブジェクトを定義したいとき、dataオブジェクトは1つのコンポーネントの全てのインスタンスで共有されてしまいます。そのためVueコンポーネントの中のdataはオブジェクトを返す関数にします。
コンポーネント間の通信
親コンポーネントと子コンポーネントのデータのやりとりを解説します。
親コンポーネントが子コンポーネントへデータを渡す際には、propsを利用します。
例を見ていきましょう。以下のように、フルーツの名前をリストするコンポーネントを作成します。ここでは配列fruitsItems
に入ったフルーツの名前fruitsItem.name
をリストするテンプレートを含んだコンポーネントを、fruits-list
という名前でVueインスタンスに登録しています。
配列fruitsは親コンポーネントのdataで定義します。
上記のように子コンポーネントのpropsオプションに変数名fruitsItems
を追加したうえで、HTML上の子コンポーネントのfruits-list
タグの属性にfruits-items
を記述します。すると、親コンポーネントから子コンポーネントに値を渡せます。
propsにキャメルケースでfruitsItems
と書いた場合、テンプレート側にはケバブケースでfruits-items
と書きます。
ここで、親のdataの変更を子に伝えるには、以下のようにv-bind
ディレクティブを使用すると良いでしょう。
このように記述すると、親コンポーネントでfruits
の値が更新されるたびに、子コンポーネントのprops
に書いたfruitsItems
が更新されます。なお、v-bind
は省略できます。
レンダリングされるHTML要素は以下のようになります。
ここまでのサンプルコードは、こちらのjsfiddleで確認できます。
子コンポーネントから親コンポーネントへの通信では、カスタムイベントを使用します。Vueインスタンスには、以下のようなイベントのインターフェイスが実装されています。
- イベントのlisten:
$on(eventName)
- イベントのtrigger:
$emit(eventName)
こちらも例を見ていきましょう。以下のようにcounter-button
コンポーネントが定義されているとします。ボタンを押すとこのコンポーネントのaddToCart
メソッドが呼ばれ、その中でincrement
というカスタムイベントが発行されます。親コンポーネント側では v-on:increment(increment)
でincrement
イベントをlistenしているため、ボタンを押した時に親コンポーネントのincrement
メソッドが呼ばれます。
ここまでのサンプルコードは、こちらのjsfiddleで実行できます。
大規模なアプリケーションを作成していると、親と子の関係以外にもコンポーネントがさまざまな関係を持つことがあります。複雑なケースについては、ストアというオブジェクトに状態を持たせてそこで管理する方法(ストアパターン)が有効です。詳しくはこちらのドキュメントを参照してください。
コンポーネントの作成
ログインフォームコンポーネントの作成
ここまでの知識を踏まえてログインフォームを作成しましょう。まずtemplateはログインIDとパスワードのinputフォームを用意し、それぞれv-model
でコンポーネントのデータとバインドしておきます。ボタンにはv-on:click(login)
と記述し、クリックイベントが発生した際にloginメソッドが呼ばれるようにしておきます。
コンポーネントのdataにはuser_id
とpassword
を返す関数を定義し、methodにはlogin
メソッドを定義しています。なお、ここでは解説のために、認証の仕組みはauth.login
という仮の関数を置いています。
以上で簡単なログイン用のコンポーネントが作成できました。このコンポーネントを、親となるコンポーネントの中で以下のように呼びだすと、ログインのUIコンポーネントを再利用することができます。
ここまでのサンプルコードは、このURLから確認できます。
ヘッダーコンポーネントの作成
より実践的な例として、Webアプリケーションのヘッダーを、再利用可能なVue.jsのコンポーネントとして作成してみましょう。ヘッダーはアプリケーションの各ページに共通して置かれることが多いため、コンポーネント化しておくと便利です。なお、ヘッダーの内容は親のコンポーネントによって変化するものとします。
まずは、あるpage
というコンポーネントの中に、ヘッダーとページのコンテンツをそれぞれ子コンポーネントとして構成した例を示します。
ここで、親のコンポーネントごとに子のコンポーネントの内容を書きかえるためにcontent distribution
という仕組みを使用します。Vue.jsのcontent distribution
のAPIは、Webコンポーネントの仕様のドラフトに基づいて設計されたものです。
たとえば、ヘッダーのコンポーネントpage-header
コンポーネントを定義するとします。
上記のようにヘッダーのコンポーネントの中にslot
というタグを埋め込みます。こうすることで親コンポーネントを使用する際に、以下のように子コンポーネントに対して埋め込みを行えます。
上記のように、親のコンポーネントを使用する際に、slot
属性に対応する子コンポーネントのslotタグのname
属性を指定することで、子コンポーネントのコンテンツをカスタマイズすることができます。レンダリングされるHTMLは以下のようになります。
ここまでのサンプルコードは、このURLから確認できます。
まとめ
いかがでしたか。ここまでVue.jsのコンポーネントの基礎について駆け足で紹介しましたが、Vue.jsのコンポーネントについてより詳しく知りたい方は、公式のドキュメントを参照してください。
次回は、Vue.jsを使用したシングルページアプリケーションの作成について紹介しますので、どうぞお楽しみに。