子コンポーネントのデータを参照するスコープ付きスロット(slot要素の属性にv-bindでバインドする) [Vue.js]

Vue.js The Progressive JavaScript Framework

前回、前々回の記事ではVue.jsのスロットを使用して、親コンポーネントから子コンポーネントへコンテンツを埋め込めることを紹介しました。

コンポーネントに指定したコンテンツを外から埋め込む<slot>要素 [Vue.js]
コンポーネントを作成していると、コンポーネント側の実装時点では配置できない要素などを利用する側から差し込みたい場合があります。 ...
名前付きスロットでコンポーネントの複数のスロットにコンテンツを埋め込む v-slot [Vue.js]
前回はコンポーネントに外部からコンテンツを埋め込むことができるスロット(slot要素)を紹介しました。 前回の記事では...

コンポーネントを利用して画面を構築していると、データ(値)は子コンポーネントで取得しておいて、親コンポーネントではそのデータ含めたHTMLテンプレート(要素)を子コンポーネントのスロットに埋め込みたい時があります。
通常は、子コンポーネント内のデータ(dataオプションに定義したデータなど)は、子コンポーネント内からしかアクセスできませんが、子コンポーネント側のデータを親コンポーネントから参照したい場合が多々あります。

Vue.jsのスロットでは、そのような場合に子コンポーネントのデータを参照できる「スコープ付きスロット」という仕組みが用意されており、親コンポーネント側で子コンポーネントのデータにアクセスしてHTML要素(タグ)の内部に配置したコンテンツを子コンポーネントのスロットに埋め込むことができるようになっています。

今回は、スロットを利用して子コンポーネントのデータに親コンポーネントからアクセスする方法について紹介します。

スコープ付きスロット

スコープ付きスロットとは、子コンポーネントのスロットにデータ(値)をバインドし、バインドしたデータに親コンポーネントからアクセスすることができるようにする機能です。

スコープ付きスロットを利用することで、データを出力するロジックを子コンポーネント側に記述し、データを出力する際のHTMLの形式やスタイルの指定を親コンポーネント側で記述することができます。

子コンポーネント側の記述

子コンポーネント側では、slot要素でスロットを定義する際にスロットにバインドするデータをv-bindディレクティブで指定します。

プロパティ名に指定する値は、親コンポーネントから参照する際に指定する名前になります。ここで指定するプロパティ(属性)のことを「スロットプロパティ」と言います。
バインドするデータには、子コンポーネント側のdataオプションに定義したプロパティなどを指定することができます。

親コンポーネント側の記述

親コンポーネント側では、HTMLテンプレートに子コンポーネントのカスタム要素を配置します。
子コンポーネントの要素の子要素としてtemplate要素を配置し、属性にv-slotディレクティブを定義します。
v-slotディレクティブには引数として子コンポーネントのスロットプロパティが格納されているオブジェクトを参照するための名前を指定します。

スロットの名前には、子コンポーネントのslot要素にname属性で設定した名前、または名前を設定していない場合は「default」を指定します。
スロットプロパティを含むオブジェクトには任意の値を指定できます。
親コンポーネントでは、ここで指定するスロットプロパティを含むオブジェクトのプロパティとして、子コンポーネントで設定したスロットプロパティを参照することができます。スロットプロパティは、スロットプロパティを含むオブジェクトの後にドットでつなげて記述します。

スコープ付きスロットの使用例

以下にスコープ付きスロットの使用例を示します。

HTML

JavaScript

ここでは、子コンポーネントでdataオプションに定義したnameとpriceの2つのプロパティを持つオブジェクトのproductプロパティとmakerプロパティを、slot要素にv-bindディレクティブでバインドしています。
親コンポーネントでは、子コンポーネントでバインドしたスロットプロパティを参照しています。
スロットプロパティを受け取るためのオブジェクトをv-slotディレクティブに「slotProps」という名前で指定しています。
子コンポーネントでバインドしたスロットプロパティには「slotProps.プロパティ名」でアクセスし、マスタッシュ構文({{}})で値を出力しています。

上記の子コンポーネントのスロット既定のコンテンツは以下のように表示されます。

スコープ付きスロットを持つ子コンポーネントの既定の出力

これをスロットを使用して親コンポーネントからコンテンツを出力すると、次のように差し替えることができます。

スコープ付きスロットを持つ子コンポーネントのスロットに親コンポーネントからコンテンツを埋め込んだ出力

上記の例では、単純なデータの参照例を記載していますが、子コンポーネントでv-forディレクティブを使用して繰り返し出力したプロパティを親コンポーネントから参照することもできます。

以下に子コンポーネントでv-forディレクティブでループして出力したプロパティのデータを、親コンポーネントで取得して新たなコンテンツとして出力する例を示します。

HTML

JavaScript

上記の例では、製品リストを表示する子コンポーネント(procudt-list)のdataオプションのプロパティに、製品情報のオブジェクトを配列で持つproductsプロパティを定義してます。
定義したproductsプロパティはHTMLテンプレートのli要素でv-forディレクティブを使用してループで処理を行っています。
li要素内のテンプレートでは、slot要素でv-bindディレクティブを使用して、ループ処理をするために取得したproductsプロパティの1要素のproductをバインドしています。

Vue.jsのスコープ付きスロットの親子コンポーネント間の関連イメージ

【補足】デフォルトスロット(default)しかない場合の省略記法

本記事でここまで示した子コンポーネントにはデフォルトスロットが1つ配置されているだけでした。
このように、デフォルトスロットだけの場合は、親コンポーネントで定義するコンポーネント要素(タグ)をスロットのテンプレートとして使用することができます。
つまり、template要素を使用することなく、コンポーネントの要素(上記の例ではproduct-list)に対して直接v-slotディレクティブでの指定を使うことができます。

Vue.js 入門 Tips 一覧