こんにちは、Nakataです。
前回はVue.jsに触れてみようという記事でVue.jsを紹介しました(前回記事)。今回はそのVue.jsの特徴である、コンポーネントについて紹介していきます。コンポーネントとはどんなものなのか、どのように使用されているのかについて、実際にコードを書いて、簡単なアプリケーションを作成しながら解説します。
コンポーネントとは
コンポーネントとは簡単に説明すると、UI(ユーザーインターフェース)を作成する要素がまとまったものです。HTML、データ、ロジック、CSSを要素としてコンポーネントに含むことができます。そのコンポーネントを組み合わせることで、Webアプリケーションを作成することができます。作成したコンポーネントには名前が付けられます。その名前を登録し呼び出すことで、必要な時に何度でもアプリケーション内で使用することができます。
この時、コンポーネントはVueインスタンスとして呼び出されUIとしての要素を持ちます。Vueインスタンスとして呼び出されるというのがどのようなことなのか、まだ理解が難しいかと思います。実際に簡単なアプリケーションを作成しながら見ていきましょう。
とりあえずコンポーネントというのは、UIに必要な要素を詰め込める名前の付いた箱のようなものであり、それを組み合わせることでWebアプリケーションを作れるものだとイメージしていただければ大丈夫です。
コンポーネントのメリット
実際に触ってみる
環境設定
前回同様、プロジェクトのテンプレートを自動で作成してくれる、vue-cliを使用します。
(vue-cliを使用するためにはNode.jsが必要です。今回はNode.js v9.11.1で動作)
以下のコマンドでwebpackのプロジェクトを作成します。
1 |
$ vue init webpack my-form-project |
プロジェクトが作成できたら、実際にサーバを動かしてみましょう。
1 2 3 |
$ cd my-form-project $ npm install $ npm run dev |
コンポーネントの作成
まずはコンポーネントを作成してみましょう。今回作成したプロジェクト内に作成された、srcディレクトリ内のファイルを書き換えていきます。src/components/HelloWorld.vueのtemplateとscriptタグ内を以下のサンプルコードに置き換えてみてください。
サンプルコード
1 2 3 4 5 |
<div class="hello"> <h1>{{ msg }}</h1> </div> |
1 2 3 4 5 6 7 8 |
export default { name: 'HelloWorld', data () { return { msg: 'HelloWorld' } } } |
HelloWorldと表示されるページができました。
続いて、HelloWorld.vueに登録するためのコンポーネントを作成していきます。ここでは、名前とコメントを入力するフォームを持ったコンポーネントFormA.vueと、年齢と住所を入力するフォームを持ったコンポーネントFormB.vueを作成します。他にも機能として、クリックすると入力された値がアラートで通知されるメソッドも追加します。src/components以下にHelloWorld.vueをコピーしてFormA.vue、FormB.vueを作成し、templateとscriptタグ内を以下のサンプルコードに置き換えてみてください。
FormA.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<div class="hello"> <h1>FormA</h1> <input type="text" v-model="name" placeholder="input your name"> <input type="text" v-model="msg" placeholder="input message"> Name:{{ name }} Message:{{ msg }} <button v-on:click="check">Check</button> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
export default { name: 'FormA', data () { return { name: '', msg: '' } }, methods: { check () { alert('Your name is ' + this.name) } } } |
FormB.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<div class="hello"> <h1>FormB</h1> <input type="text" v-model="age" placeholder="input your age"> <input type="text" v-model="address" placeholder="input your address"> Age:{{ age }} Address:{{ address }} <button v-on:click="check">Check</button> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
export default { name: 'FormB', data () { return { age: '', address: '' } }, methods: { check () { alert('Your age is ' + this.age + '\nYour address is ' + this.address) } } } |
コンポーネントの登録、再利用方法
作成したFormA.vue、FormB.vueをHelloWorld.vueに登録して利用してみましょう。HelloWorld.vueのtemplateとscriptタグ内を以下のサンプルコードに置き換えてみてください。
サンプルコード
1 2 3 4 5 6 7 |
<div class="hello"> <h1>{{ msg }}</h1> <form-a /> <form-b /> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import FormA from './FormA.vue' import FormB from './FormB.vue' export default { name: 'HelloWorld', components: { FormA, FormB }, data () { return { msg: 'HelloWorld' } } } |
作成した入力フォームが追加されているのが確認できたでしょうか。checkをクリックすると入力した値がアラートされるのも確認してみてください。
scriptタグ内のimport FormA from ‘./FormA.vue’でFormA.vueのインポートを行い、components:にFormAを追加することで、HelloWorld.vueでFormA.vueを利用することができます。templateタグ内のフォームを追加したい場所にと書き込むことでコンポーネントFormA.vueの利用ができます。また、一度登録したコンポーネントは何度でも再利用することが可能であるため、次のサンプルコードのようにHelloWorld.vueのtemplateタグ内にを追加することで同じフォームがページに追加されます。
サンプルコード
1 2 3 4 5 6 7 8 |
<div class="hello"> <h1>{{ msg }}</h1> <form-a /> <form-a /> <form-a /> </div> |
同じフォームがページに追加されたのが確認できたでしょうか。次はdataの扱いについて見てみましょう。1つのフォームにnameを入力しても、同じFormA.vueから作成された他のフォームのnameは変更されません。これはコンポーネントを利用するたびに、それぞれ新しいインスタンスが作成されるからです。dataはインスタンスごとに定義されているため、同じ名称でも別のものとして扱われます。
既に不思議に思っていた方もいるかもしれませんが、HelloWorld.vueで定義されているmsgと、FormA.vueで定義しているmsgの値も別のものとして扱われています。ですが、コンポーネントを登録した側と登録される側で、dataの値を受け渡しを行う方法もあります。詳しくは次回以降の記事で解説させていただきます。
動的なコンポーネント
次に動的にコンポーネントを使用してみましょう。まずは、HelloWorld.vueのtemplateとscriptタグ内を以下のサンプルコードに置き換えてみてください。
サンプルコード
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="hello"> <h1>{{ msg }}</h1> <span>Selected: {{ selectedComponent }}</span> <input type="radio" id="FormA" value="FormA" v-model="selectedComponent"> <label for="FormA">FormA</label> <input type="radio" id="FormB" value="FormB" v-model="selectedComponent"> <label for="FormB">FormB</label> <component :is="selectedComponent"> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import FormA from './FormA.vue' import FormB from './FormB.vue' export default { name: 'HelloWorld', components: { FormA, FormB }, data () { return { selectedComponent: '', msg: 'HelloWorld' } } } |
FormAかFormBを選択する画面が表示されたでしょうか。チェックボックスを選択すると対応したフォームが表示されます。ここで動的にコンポーネントが生成されています。
では、どのような仕組みで動的にコンポーネントが生成されるか見てみましょう。
まずdataのselectedComponentに、チェックボックスで選択したFormAかFormBが値として与えられます。選択した値は<component :is=”selectedComponent”>の行で使用されますが、ここでインスタンスが生成されています。<component>要素内の特別な属性isに、登録されたコンポーネントの名前を与えることで、与えた名前のインスタンスが生成される仕組みになっています。
また、コンポーネント名を選択する度に新しくインスタンスが生成されるため、dataの値は保存されていません。FormAにnameを入力してからFormBに切り替え、もう一度FormAに戻って入力された値が消えているのを確認してみてくだい。このように動的にコンポーネントを生成する際、dataの状態は保存されません。
しかし、フォームの切り替え機能として利用する等、変更したdataの状態が保存された方が望ましい場合もあります。その解決策として<keep-alive>要素を使用する方法があります。HelloWorld.vueのtemplateタグ内を以下のサンプルコードに置き換えてみてください。
サンプルコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<div class="hello"> <h1>{{ msg }}</h1> <span>Selected: {{ selectedComponent }}</span> <input type="radio" id="FormA" value="FormA" v-model="selectedComponent"> <label for="FormA">FormA</label> <input type="radio" id="FormB" value="FormB" v-model="selectedComponent"> <label for="FormB">FormB</label> <keep-alive> <component :is="selectedComponent"> </keep-alive> </div> |
コンポーネントを切り替えても、入力された値が保存されているのが確認できたでしょうか。
このように<keep-alive>要素を使用することで、動的に生成されたコンポーネントの状態の変化を残しておくことができます。
最後に
今回はコンポーネントとはどんなものか、コンポーネントの作成方法、再利用する方法、動的に使用する方法について紹介をしました。コンポーネントを使用し開発をしていく上で、便利な機能は他にも多く存在します。次回以降また紹介していきたいと思います。