【vue】 コンポーネントの使い方
vueにおけるコンポーネントは、オブジェクト指向におけるクラスとに似ています。コンポーネントを使うことでクラスのように関心を切り分けることができます。
シングルファイルコンポーネントについては下の記事にあります。
使い方
コンポーネントはクラスのようなものです。コンポーネントを作ることで関心を切り分けたり、複製して効率よく使い回すことができます。
コンポーネントを作る
例えば、クリックしたらその回数をカウントするコンポーネントを作成してみます。
const app = Vue.createApp({ // ... }); // ボタンのコンポーネント app.component('button-counter', { data() { return { count: 0, } }, methods: { addCount(v) { this.count += 0; } }, template: ` <div> <button @click="addCount(2)">クリック!</button> <p>クリック回数: {{ count }}</p> </div> `, });
template
の中身は文字列で、バッククォートで囲むことで複数行書けるようにしています。
コンポーネントには、普通にcreateApp
に書くものとおおよそ同じ内容を書きますが、引数とtemplate
が追加されています。
app.component
の第1引数にはコンポーネントの名前を、第2引数にはそのコンポーネントの中身を記入します。
template
には、実際に表示するHTMLを書きます。v-for
なども同様に使用できます。
template
の中身のHTMLは、必ず1つの要素である必要はありません。
しかし、コンポーネントで表示している部分を明確にすることで、CSSの適用がしやすくなったり、DOMの構造がわかりやすくなります。
コンポーネントを使う
コンポーネントは、HTML側でapp.component
に設定した名前と同じ名前で、HTMLタグに用に書きます。
<div id="app"> <button-counter></button-counter> </div>
これは、クラスのインスタンスを作成しているのと似ています。表示される際は、上で設定したtemplateの内容 (v-forなどはコンポーネント内で処理される) が表示されます。
そのため、複数の同じコンポーネントを配置できます。
<div id="app"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
そして、それぞれが持っているdata
の値は、クラスと同じように独立しています。
See the Pen vue component2 by Totori (@souki202) on CodePen.
このように、vueにおけるコンポーネントとその利用は、クラスの宣言とインスタンスの作成の概念に似ていますね。

propsで値を渡す
クラスを作るときにコンストラクタに引数を渡せるように、コンポーネントをHTMLにタグで書く際に値を渡すことができます。
受け取る側は、props
を用意して変数の箱を作ります。props
に入ってきた値は、data
と同じように読み出すことができます。
app.component("button-counter", { props: ["addValue"], data() { return { count: 0, } }, methods: { addCount() { // 送る側がv-bindでないため, 文字列になっている this.count += Number(this.addValue); } }, template: `...`, });
<button-counter add-value="3"></button-counter>
ここで、渡すときの注意点として、props
はスネークケース(add_value
)やキャメルケース(addValue
)で書きますが、キャメルケースの場合、HTMLでは必ず-
で区切る (ケバブケース) ようにする必要があります。
props | html |
---|---|
foo | foo |
fooBar | foo-bar |
foo_bar | foo_bar |
app.component("button-counter", { props: ["addValue"], // ... });
<!-- ケバブケースになる --> <button-counter add-value="3"></button-counter>
props側の名前がスネークケースの場合、HTML側も<button-counter add_value="3"></button-counter>
のようにスネークケースで書きます。
v-bindで値を渡す
v-bind
を利用して渡すこともできます。この場合、propsで送る値と受け取る値の型は一致します。
オブジェクトも渡せます。
<div id="app"> <div v-for="i in 3"> <button-counter :addValue="i"></button-counter> </div> </div>
See the Pen by Totori (@souki202) on CodePen.
propsの制約
props
にある値はdata
と同じように読み出す事はできますが、更新することはできません。つまり親から子の一方通行です。props
の値をコンポーネント内でv-model
に利用したりなどはできません。
子コンポーネント内だけで更新したい場合、そのコンポーネント内でdata
に代入して使う方法があります。ここで、配列やオブジェクトの場合は参照渡しされるため、その中の値を書き換えると親や他に渡したコンポーネントの値も連動してしまうので注意してください。
app.component("button-counter", { props: ["value"], data() { return { // ここでdataに入れて, 子コンポーネント内のメンバ変数のような感じにする myValue: this.value }; }, methods: { f() { <!-- this.value = 10; // propsの変数に代入はNG!! --> this.myValue = 10; // dataの変数なのでOK } } // ... }
配列を渡した場合は参照が渡されるため、連動して変わってしまう例です。
See the Pen vue component prop3 by Totori (@souki202) on CodePen.
親コンポーネント側の値が書き換わるようにもできますが、それは別の場所でprops
を掘り下げます。
v-modelを使用して子から親に値を伝える方法は下の記事で説明しています。
ただ、先にemitについて知っておくべきです。
コンポーネントがコンポーネントを持つ
クラスが別のクラスのインスタンスを持てるように、コンポーネントが別のコンポーネントを表示することができます。
app.component("header-component", { data() { return {}; }, template: ` <header> <p>header component</p> <!-- header-componentがbutton-counter呼び出し --> <button-counter v-for="i in 3" :addValue="i"></button-counter> </header> ` });
See the Pen vue component3 by Totori (@souki202) on CodePen.
まとめ
コンポーネントは、クラスのような感覚で扱うことができます。しかし、このままでは使いづらいので、次はコンポーネントを1つのファイルにして管理してみましょう。
1つのvueファイルにコンポーネントを切り出したい場合は、下の記事で説明しています。
