2019/12/12vue.jsコンポーネントの基礎Vueコンポーネントはvue.jsの中核をなす重要な機能です。コンポーネント間のデータの受け渡しや記述方法など最初は難しさを感じるかと思います。本文書を参考にコンポーネントの理解を深めてください。slotに名前をつけるコンポーネントとは企業HPやブログのサイトを見るとヘッダー、フッター、メイン、サイドバーというようにいくつかのパーツに別れて構成されています。ヘッダーやフッターなどはどのページでも同じ内容の場合が多く1つのデータを共有する仕組みを使って構築するのが一般的です。このようにパーツ化し共有化することで開発、メンテナンスの効率が格段に上がります。vue.jsではコンポーネントという機能を使って部品化し再利用することで効率よく開発、メンテナンスを行うことができます。コンポーネントの設定コンポーネントの作成コンポーネントを利用するためには、コンポーネントを定義して登録する必要があります。methods等のプロパティを持つことができます。記述方法や使い方は、これから順次説明を行っていきます。実際に使用する場合は下記のように記述します。World</h1>'})コンポーネントの登録を行うとVueインスタンス下にあるhtml内から直接コンポーネントを利用することができます。利用する場合は、コンポーネント作成時に設定した名前のタグを使ってhtmlに組み込みます。Vueのelで指定しているidタグの中の要素のことを意味します。本文書では#appです。id="app"><hello-world></hello-world></div>コンポーネントの名前は任意のため、その中に記述する内容を要約した名前をつけることでメンテナンスも楽になります。ブラウザで見ると登録したコンポーネントのtemplateプロパティのh1タグの内容が表示されることが確認できます。WorldVueインスタンスを含めたコード全体は下記のようになります。cdnを使ってvue.jsを読み込んでいます。Vueよりも前に記述する必要があります。correctly?のメッセージがコンソールに表示され、ブラウザには何も表示されません。エラーメッセージを日本語にすると”コンポーネントは正しく登録されましたか?”という内容です。本文書では、vue.jsが設定通りに動作しない場合はコンソール(console)を使ってエラーを確認します。elementもコンソールを使って確認しています。Chromeの場合、開発ツール(デベロッパーツール)から確認することができます。あわせて読みたいWEB制作での開発ツールの使い方Chrome編(基礎)コンポーネントの再利用コンポーネントは再利用することができます。hello-worldのタグを複数記述するだけで同じ内容を表示させることが可能です。コンポーネントを一度作成すると部品としてどこからでも利用することができます。先ほどはVue.componentを利用してコンポーネントの登録を行いました。コンポーネントの登録には、グローバルとローカルがあります。Vue.componentを使う場合はグローバルへの登録となり、別のコンポーネントで利用することができます。ある特定のコンポーネントだけで利用したい場合にローカルに登録し利用することができます。ローカルへの登録は、Vueインスタンスにcomponentsプロパティの追加をすることで行います。}})グローバルとローカル登録の違いVue.componentを使ったグローバル登録とVueインスタンスの中で行うローカル登録の違いは下記の例で理解することができます。1つのページに2つのVueインスタンスを作成し、hello-worldのコンポーネントはグローバル登録、hello-viewのコンポーネントは2つめのapp2インスタンスのみに登録します。vue.jsでは、id=”app”とid=”app2′′を要素として2つのVueインスタンスを1つのページ内で作成することができます。Viewの文字列が表示されませんが、ローカル登録したapp2のVueインスタンス側には表示されます。correctly?。不明のカスタムエレメント、正しくコンポーネントを登録しましたか?のエラーが表示されます。templateに複数のタグtemplateに複数のタグを入れる場合に注意点があるので確認しておきます。以下のようにtemplateの中にpタグを2つ挿入します。Worldが画面には表示されません。とエラーメッセージが表示されます。エラーの内容は”コンポーネントテンプレートは1つのルート要素を持たなければならない”というエラーです。上記ではpタグが2つ挿入されているため、1つのルート要素にはなっていません(2つのルート要素になっている)。そのため、この2つのpタグを含む上位のタグをつける必要があります。ここではdivタグをつけます。Worldが表示されます。}})1つのルートタグ忘れはよく発生しがちなミスなのでこのルールはしっかりと記憶しておきましょう。コンポーネントでdataを使うtemplateを追加してh1タグでブラウザに表示を行いました。コンポーネントでは、templateにhtmlタグを挿入するだけではなくdataも使用することができます。dataの設定方法はVueインスンス作成時と同じですが、dataは関数にする必要があります。}})複数のdataを使いたい場合は下記のようになります。}以下はVueインスタンスの場合のdataの記述方法です。違いをしっかりと覚えておいて記述間違いをしないように注意しましょう。dataを関数にすることでdataを持つ複数のコンポーネントを使った場合にコンポーネント毎にdataの独立の値を保持することができます。次の”メソッドを追加する”の例を通してコンポーネント毎に独立した値を持つという意味を理解してください。}メソッドを追加するコンポーネントはdataだけではなくメソッドも使うことができます。メソッドの追加はVueインスタンス作成時と同じ方法でmethodsプロパティで行います。例を使ってコンポーネントのメソッドを理解していきます。コンポーネントの名前をbutton-counterとして、dataにcount変数を持たせ、countUp、countDownの2つのメソッドを追加します。ボタンにはv-onディレクティブでclickイベントを設定して、Upボタンを押すとcountが1増え、Downボタンを押すとcountが1減るプログラムを作成します。}})htmlにはbutton-counterタグを追加します。id="app"><button-counter></button-counter></div>Upボタンを押すとカウントが増え、Downボタンを押すとカウントが減ります。コンポーネントを使ってカウンターを作成することができました。コンポーネントでカウンター作成コンポーネントは再利用できることを先ほど学んだので、button-counterタグを複数設定してみましょう。<button-counter></button-counter></div>コンポーネントを複数作成した場合それぞれが独立したものとして作成されるので、Up、Downボタンはそのコンポーネント内のbutton-counterのみ影響を与えることができるため、countの値もそれぞれのコンポーネントで別々の値を保持することできます。複数のカウンターを表示template内のhtmlを改行する下記のようにtemplateに指定するタグが長い場合に途中で改行したい場合があります。シングルクオテーションで囲まれている場合は途中で改行を行うと正常に動作しません。v-on:click="countDown">Down</button></p>',templateで設定するhtmlが長い場合は、`(バッククォート)を使用してください。下記は意図的にタグごとに改行していますが、改行を行なってもプログラムは正常に動作します。</p>`,データの受け渡し(親→子)ここまでの説明でコンポーネント単独での利用方法がわかりました。次はコンポーネント間でのデータの受け渡しの説明を行います。コンポーネント間のデータの受け渡しができれば、別々に作成されたコンポーネントを連携して利用することができます。親コンポーネントから子コンポーネント、子コンポーネントから親コンポーネントと異なる方法でデータの受け渡しを行うので、混乱しないように注意する必要があります。Worldの例では、親コンポーネントは、hello-worldのコンポーネントを利用したVueインスタンスです。子コンポーネントはVue.componentで作成したhello-worldに対応します。ここでは行いませんが子コンポーネント(hello-world)のtemplateプロパティでは、別のコンポーネントを利用することができます。その場合はhello-worldが親のコンポーネントになり、利用された別のコンポーネントが子コンポーネントになります。親と子の関係もしっかり理解してください。親から子へのデータの受け渡し親コンポーネントから子コンポーネントへのデータの受け渡しには、propsを使用します。['message']})ここでのデータはVueインスタンス内にあるdataプロパティのデータではありません。後ほど説明しますが、dataプロパティの場合はv-bindを利用して渡します。親コンポーネントはmessage属性としてその値を渡します。Vue"></hello-world></div>ブラウザで確認するとmessage属性の値が親コンポーネントから子コンポーネントに渡され表示することが確認できます。}})</script></body></html>親のdataを子へv-bindを使うことで親コンポーネントのdataを子コンポーネントに渡すことができます。inputTextを親コンポーネントのdataに追加します。}})Vue.componentは先ほど同様にmessage属性を使って親からデータを受け取ります。['message']})message属性をv-bindし、その値はdataプロパティのinputTextを設定します。これだけでinputTextの値は子コンポーネントに渡されますが親で変更されたinputTextが即座に反映されるのか確認するためにinput要素を追加して、v-modelでinputTextをバイディングします。v-bind:message="inputText"></hello-world></div>フォームに入力した内容が即座にブラウザに反映されることが確認できます。v-modelを使用したコンポーネントリストデータを子に渡すv-forディレクティブを利用して、リストデータを子コンポーネントに渡すこともできます。dataにリストデータの追加を行います。}})v-forを使用し、値を渡す時にpostオブジェクトとして渡すことができます。keysのメッセージが表示されます。v-forではkeysを設定して実行することを進めるメッセージです。ブラウザ側にはエラーが表示されませんが、コンソールにはメッセージがでているのでkeyを設定するようにしてください。keyを設定する理由は知りたい人は下記が参考になります。子コンポーネントはpostをオブジェクトとして受け取り、templateの中でpostの展開を行います。['post']})ブラウザでもpost毎にリストが展開されて表示されることを確認することができます。先程はpostオブジェクトを渡して子コンポーネントで展開しましたが、オブジェクトではなく変数として渡すこともできます。v-bind:content="post.content"></blog-post></div>dataを受け取る側の子コンポーネントのpropsで受け取るそれぞれの属性名を設定します。['title','content']})データの受け渡し(子→親)親から子へdataを渡したい場合はv-bindとpropsを使いました。子から親にdataを渡したい場合は、$emitというメソッドとイベントを利用して行います。propsでのデータ渡しに比較して複雑で最初は難しいと感じるかもしれませんが慣れていきましょう。読み進めるためには、v-onディレクトリを使ったイベントの処理は理解しておく必要があります。$emitを使って子から親へ子から親へのデータの受け渡しは少し複雑ですが、一度自分の手を動かして設定を行えば比較的楽に理解することができます。$emitを使った子コンポーネントから親コンポーネントへのデータの受け渡しの流れです。子コンポーネント側でボタンに対してクリックイベントを設定します。クリックイベントが発生したら、子コンポーネントはそのイベントの処理(clickEvent)で$emitメソッドを実行し、親に渡したいイベント(from-child)を発生させます親は子からくるイベントに対するalertMessageメソッドを設定しfrom-childイベントを待ちます。親は子が発生させたイベント(from-child)を受け取ってalertMessageメソッドを実行します。}3.親は子からくるイベントに対するalertMessageメソッドを設定しfrom-childイベントを待ちます。v-on:from-child="alertMessage"></emit-event></div>4.親は子が発生させたイベント(from-child)を受け取ってalertMessageメソッドを実行します。}})</script></body></html>子コンポーネントでv-on:clickの値にそのまま$emitを記述することもできます。記述をすることでclickEventメソッドも必要ではなくなります。v-on:click="$emit('from-child')">ボタン</button>`,子から親へdataを送る先程の例では、子で発生させたイベントを使って親に伝えることはできました。次は、子コンポーネント側のdataを親側に送ってみましょう。子コンポーネントに入力フォームを作成し、入力後送信ボタンを押すとイベントが発生し、$emitメソッドを利用して、入力した内容を親に送ります。},})templateの文字が長くなったので改行を行っています。1行の場合はシングルクオート(‘)でしたが、複数の場合は、バッククオート(`)を使います。バッククオートはキーボードの@の場所にあります。$emitは引数を取ることができ、この引数を利用してデータを送ります。複数のデータを渡す場合はオブジェクトを利用して渡すことができます。this.$emit('from-child',this.inputText,XXX)親側で子からのイベントの設定を行います。v-on:from-child="receiveMessage"></emit-event></div>receiveMessageメソッドは受け取ったmessageをdataのmessageに設定します。}})子コンポーネントのフォームに入力したテキストが親コンポーネントに渡され、ブラウザに表示することを確認できます。子からデータを受け取ったコンポーネントとSlot(スロット)slotの機能を利用すると親側でコンポーネントタグの間に挿入した内容を子コンポーネント側で表示することができます。Slotについてはvue.js2.6+で記述方法に変更もありました。Slotについては下記の文書を読むことをおすすめします。親側で下記のように子コンポーネントタグの間にコンテンツを挿入します。<slot-test>スロットによる挿入</slot-test></div>子側のコンポーネントでは親側で挿入されたコンテンツを表示させる場所にslotタグを入れておきます。'<p><slot></slot></p>',}),ブラウザで確認すると親側で子コンポーネントタグの間に挿入したコンテンツが下記のように表示されます。slotを使用して表示slotの初期値の設定slotタグの間に初期値を設定することで親側からのSlotの挿入がない場合は設定した初期値を表示させることができます。'<p><slot>デフォルト</slot></p>',})親側で挿入するコンテンツがあるものとないもの2つのコンポーネントタグを記述します。<slot-test></slot-test></div>挿入がない場合は、初期値であるデフォルトが表示されることが確認できます。slotに初期値がある場合slotに名前をつける先程まではslotに挿入できる内容は1つでしたが、複数ある場合は表示させる場所を識別するためslotに名前をつけることができます。slotタグにname属性をつけその値にslot名を設定することで識別します。</div>`,})slotを挿入する親側ではタグにslot属性を追加しその値に子コンポーネントで定義されているslotの名前を入力してその間に渡したいコンテンツを挿入します。</slot-test></div>ブラウザで確認すると指定したslot名の通りにコンテンツが表示されることが確認できます。slotに名前をつけるHTMLのソースを確認するとslot属性を設定したdivタグとpタグも一緒に表示されます。pタグを表示させないため、templateタグに変更を行います。templateタグを利用すると先ほどまでコンソールに表示されていたdivタグとpタグが表示されなくなり期待通りのタグ設定になります。slotに名前をつける。