はじめに
私自身がslotについて調べてわかったことについてまとめました。
slotって?
slotは親コンポーネントから子コンポーネントにデータを渡す手段です。
slotを利用して子コンポーネントのデータを取り出して親コンポーネントで利用することはできません。(実はできますが、きっとやらないでしょう)
子コンポーネントからデータを取り出したい場合はemit等を利用しましょう。
slotの基本
以下は仮に「my-hello」コンポーネントがあると想定し、データの渡し方と受け取ったデータの使い方を紹介します。
親コンポーネント側の記述方法(データの渡し方)
<!-- コンポーネントタグで渡したいデータを挟む -->
<my-hello>vue.js</my-hello>
コンポーネントタグで渡したいデータを囲むことでコンポーネントにデータを渡すことができます。
子コンポーネント側の記述方法(受け取ったデータの使い方)
const MyHello = {
template: `
<!-- 受け取ったデータがslotタグが囲んだ中に表示される -->
<div>こんにちは、<slot>xxx</slot>さん!</div>
`,
}
slotタグで囲んだところに受け取ったデータが表示されます。
上記の例では以下のhtmlが生成されます。
<div>こんにちは、vue.jsさん!</div>
データはマスタッシュ構文等でリアクティブに渡すことも可能です。
データは文字列だけでなく、データを渡す側でhtmlの構文に則って記述することでレイアウトも指定することが可能です。
v-slotを利用して複数のデータを渡す
親コンポーネント側の記述方法(データの渡し方)
<my-hello>
<p>ゲスト0</p>
<template v-slot:guest1>ゲスト1</template>
<template v-slot:guest2>ゲスト2</template>
<template v-slot:default><p>ゲスト3</p></template>
<p>ゲスト4</p>
</my-hello>
子コンポーネント側の記述方法(受け取ったデータの使い方)
const MyHello = {
template: `
<div>こんにちは、<slot name="guest1">xxx</slot>さん!</div>
<div>こんにちは、<slot name="guest2">xxx</slot>さん!</div>
<div><slot>xxx</slot></div>
`,
}
<template v-slot:guest1>
で指定した内容が<slot name="guest1">
に表示され、
<template v-slot:guest2>
で指定した内容が<slot name="guest2">
に表示され、
v-slotで指定しなかった内容や<template v-slot:default>
で指定した内容、は全て<slot>
に表示されます。
上記の例では以下のhtmlが生成されます。
<div>こんにちは、<slot name="guest1">ゲスト1</slot>さん!</div>
<div>こんにちは、<slot name="guest2">ゲスト2</slot>さん!</div>
<div>
<p>ゲスト0</p>
<p>ゲスト3</p>
<p>ゲスト4</p>
</div>
v-slotによりslotタグのname属性の値を指定し、紐づけることができ、複数の値を指定することができます。
v-bind
ならば「:」やv-on
ならば「@」のようにv-slot
ならば「#」に省略することもできます。
slot内で子コンポーネントのデータにアクセスする方法
親コンポーネント側の記述方法(データの渡し方)
<my-hello>
<template v-slot:default="slotProp">
<div>
<p>こんにちは、{{slotProp.guest.name}}さん!</p>
<p>{{slotProp.guest.age}}歳ですね。</p>
</div>
</template>
</my-hello>
親コンポーネントでv-slot:default="slotProp"
と記述することで子コンポーネントのプロパティにアクセスできるようになります。
子コンポーネント側の記述方法(受け取ったデータの使い方)
const MyHello = {
data() {
return {
guest: {
name: 'ゲスト1',
age: 28,
},
};
},
template: `
<slot v-bind:guest="guest">xxx</slot>
`,
}
コンポーネント側でv-bind:guest="guest"
と記述することでguestプロパティとdataのguestを紐づけています。
これによって親コンポーネントで、slotProp.guest
と記述することでdataのguestにアクセスできるようになります。
上記の例では以下のhtmlが生成されます。
<div>
<p>こんにちは、ゲスト1さん!</p>
<p>28歳ですね。</p>
</div>
この機能はデータは同じだけれどもテンプレートを要所で変更したいケースで使いやすそうです。
番外編:力ずくでデータを取り出す方法
上記の例を改造して子コンポーネントのdataのguest
を取り出してみます。
親コンポーネント側の記述方法(データの渡し方 受け取ったデータの使い方)
const = MyParent{
data(){
return {
guestName: null,
};
},
template: `
<div>
<my-hello>
<template v-slot:default="slotProp">
<!-- データを受け取る -->
<div style='display:none;'>{{ guestName = slotProp.guest.name }}</div>
</template>
</my-hello>
{{ guestName }}
</div>
`,
components: {
'my-hello': MyHello,
},
}
子コンポーネント側の記述方法(受け取ったデータの使い方 データの渡し方)
const MyHello = {
data() {
return {
guest: {
name: 'ゲスト1',
age: 28,
},
};
},
template: `
<slot v-bind:guest="guest">xxx</slot>
`,
}
上記の例では親コンポーネントで<template v-slot:default="slotProp">
の中でのみguestデータにアクセスできるのでその中で親コンポーネントのdataのguestName
にデータを代入して取り出しています。こんな使い方をするのは是非やめてください。
参考