スロットとは
スロットは親コンポーネントから子コンポーネントへテンプレートの一部受け渡して埋め込む能です。
データを子コンポーネントに受け渡すのであればpropsで受け取ることができますね。
スロットは表示をそのまま変えるようなときに利用できそうです。
では、実際にわかりやすいサンプルを動かしてみましょう。

スロットコンテンツ
親コンポーネントから子コンポーネントを指定する際に、子コンポーネントのタグで囲った値が子コンポーネントの<slot>要素と紐付いており、<slot>要素は描画される際に指定された値で置換されます。
親コンポーネント
<div id="app" v-cloak>
<example-component>hello world!</example-component>
</div>
子コンポーネント
<template>
<div>
Slot Message : <slot></slot>
</div>
</template>
app.js
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
var app = new Vue({
el: '#app',
data: {
},
})
これを画面で確認すると
Slot Message : hello world!
と表示されて、子コンポーネントの<slot></slot>が親コンポーネントで渡したhello world!に置換されていることが確認できました。
コンパイルスコープ
スロットの中でデータを扱いたい場合の方法です。
親コンポーネント(blade)
<div id="app" v-cloak>
<example-component>@{{ message }}</example-component>
</div>
子コンポーネント
<template>
<div>
Slot Message : <slot></slot>
</div>
</template>
app.js
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
var app = new Vue({
el: '#app',
data: {
message: 'hello world!'
},
})
こちらを画面で確認すると
Slot Message : hello world!
と表示されており、親コンポーネントのデータがslotで子コンポーネントに描画できていることが確認できました。
これは親テンプレートは親のスコープでコンパイルされ、子はこのスコープでコンパイルされていることを意味しており、これによって親コンポーネントで子コンポーネントのスコープにアクセスはできないということがわかります。
フォールバックコンテンツ
slotのデフォルト値を設定しましょう。
親コンポーネントから子コンポーネントになにも渡されていない場合に出力するテンプレートを<slot></slot>の中に記載することができます。
親コンポーネント
<div id="app" v-cloak>
<example-component></example-component>
</div>
子コンポーネント
<template>
<div>
Slot Message : <slot>default</slot>
</div>
</template>
app.js
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
var app = new Vue({
el: '#app',
data: {
message: 'hello world!'
},
})
こちらを画面にて確認すると
Slot Message : default
となっていることが確認できました。
名前付きスロット
親から子へ複数のスロットを受け渡したい場合にはスロットに名前を付けることで実現可能です。
親コンポーネントで子コンポーネントを指定する際にタグの中に、<template>タグを使ってv-slotディレクティブの引数にスロット名を指定することで<template>の中に書かれた要素が子コンポーネントへ渡されます。
また子コンポーネントでは<slot>がもっているname属性にスロット名を指定することで、親コンポーネントから渡されるスロットと紐付けることができます。
またこれまでのように名前をつけていなかったり<template>囲っていないようなスロットはdefaultという名前をもっており、<template v-slot:default>と同義となり子コンポーネントでは<slot></slot>によって描画できます。
親コンポーネント
<div id="app" v-cloak>
<example-component>
<template v-slot:header>
this is header
</template>
@{{ message }}
<template v-slot:footer>
this is footer
</template>
</example-component>
</div>
子コンポーネント
<template>
<div>
<header>
header :<slot name="header"></slot>
</header>
<main>
main :<slot></slot>
</main>
<footer>
footer :<slot name="footer"></slot>
</footer>
</div>
</template>
app.js
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
var app = new Vue({
el: '#app',
data: {
message: 'hello world!'
},
})
こちらを画面にて確認すると
header : this is header
main : hello world!
footer : this is footer
と表示され、名前を付けたスロットやデフォルトが適切に描画されていることが確認できました。
スコープ付きスロット
次は子から親にデータを受け渡します。
子コンポーネントでslot要素の属性として渡したいデータをバインドします。親コンポーネントで子コンポーネントからのデータ(スロットプロパティ)を受け取るためにはtemplete要素のv-slotの値として名前を定義する必要があります。定義したプロパティに子要素でバインドした名前をつなげて呼び出すことができます。
親コンポーネント(blade)
<div id="app" v-cloak>
<example-component>
<template v-slot:default="slotProps">
recieved @{{ slotProps.childMessage }}
</template>
</example-component>
</div>
子コンポーネント
<template>
<div>
slot :<slot v-bind:childMessage="exampleMessage"></slot>
</div>
</template>
<script>
export default {
data: function () {
return {
exampleMessage: 'Example!'
}
}
}
</script>
app.js
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
var app = new Vue({
el: '#app',
data: {
message: 'hello world!'
},
})
こちらを画面にて確認すると
slot : recieved Example!
と表示され、子コンポーネントのデータが親コンポーネントに渡され描画され子コンポーネントに挿し込まれていることが確認できました。
まとめ
公式の説明だけみても例があんまりよくなくわかりづらかったですが、実際に簡単なものを動かしてみるとわかりやすかったのでみなさんの参考になれば幸いです。
コメント