スロットとは?
親コンポーネント側から、子コンポーネントのテンプレートの一部を差し込む機能のことです。
用途
コンポーネントにコンテンツを埋め込んだり、テンプレートの一部をカスタマイズしたい場合に使う機能です。
propsとの違い
propsの場合はどのように描画するかを子コンポーネントが決めることになってしまいます。slotの場合はどのようなHTMLを差し込むかを親が決めることになります。もし、propsでslotでできることと同じことをしようとすると条件分岐が子コンポーネントに生まれることになり、コンポーネントの汎用性や保守性が損なわれてしまいます。
親子間でデータ単体ではなく、明確な描画内容を指示するとわかっている場合はslotを使った方が良いでしょう。(例えば、ログインしているユーザーによって表示するアイコンを切り替える場合等)
「デフォルトスロット」を使用した実装例
template内で、slotというタグを使うことで、リアクティブデータを、コンポーネントのテンプレートの中に差し込んでいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>test</title> </head> <body> <div id="app"> <slot-test>田中</slot-test> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script> <script> Vue.component('slot-test', { template: '<div>こんにちは、<slot>xxx</slot>さん!</div>' }); new Vue({ el: '#app' }); </script> </body> </html> |
デフォルトスロット
「<slot-test>田中</slot-test>」としている「田中」の部分は「デフォルトスロット」といい、コンポーネント側の「<slot><slot>」の位置に自動で出力されます。
実行結果
「名前付きスロット」を使用した実装例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>test</title> </head> <body> <div id="app"> <slot-test> <span slot="login">田中</span> <span slot="footer">今日の天気は曇りです。<span> </slot-test> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script> <script> Vue.component('slot-test', { template: '<div>'+ '<div>こんにちは、<slot name="login">xxx</slot>さん!</div>'+ '<footer><slot name="footer"><slot></footer>'+ '</div>' }); new Vue({ el: '#app' }); </script> </body> </html> |
呼び出し元には、「slot="呼び出すスロット名"」、呼び出し先には「name="スロット名"」という形で定義をすることで、それぞれ色んな場所に埋め込むことが可能です。
実行結果
v-slot
名前付きスロットはVue.jsのバージョン2.6以降だとv-slotで記述するというのが推奨されています。v-slotは通常の名前付きスロットと異なりtemplateタグを使います。呼び出し元の記述を「slot="呼び出すスロット"」ではなく「v-slot:呼び出すスロット名」としましょう。呼び出し先が「name="スロット名"」とするのはかわりません。なお、v-slotでのデフォルトスロットは「v-slot:default」と記述できます。
1 2 3 4 5 |
<子コンポーネント名> <template v-slot:スロット名> タグ内容 </template> </子コンポーネント名> |
動的スロット名
下記のように指定する事でスロット名を動的に変更する事が可能です。
1 2 3 4 5 |
<子コンポーネント名> <template v-slot:[data名等]> タグ内容 </template> </子コンポーネント名> |
v-slotの省略記法
「v-slot:」という記述は「#」に置き換える事が可能です。
1 2 3 4 5 |
<子コンポーネント名> <template #スロット名> タグ内容 </template> </子コンポーネント名> |
スロットの注意点
渡すHTML内にdataを使っていた場合は渡す親側のdataが参照されます。子から親にデータを渡したい場合は後述するスロットプロパティを使います。(正直あまり使いませんが。。)
子から親にデータを渡す(スロットプロパティ)
正直あまり使わないですが、slotを使えば子から親へデータを渡すことが可能です。
親コンポーネント側の記述方法
1 2 3 4 |
<template v-slot:スロット名="プロパティ名"> {{プロパティ名}} //子コンポーネント側の属性の値が全て出力される。 {{プロパティ名.属性名}} //子コンポーネント側の特定の属性の値が出力される。 </template> |
子コンポーネント側の記述方法
1 |
<slot name="スロット名" :属性名=データ1 属性名2=データ2></slot> |
一つしかv-slotのtemplateがない場合
なお、v-slotのtemplateが一つしかない場合は子コンポーネント名に直接v-slotタグを使用する事が可能です。
1 2 3 4 |
<子コンポーネント名 v-slot:default="プロパティ名"> {{プロパティ名}} //子コンポーネント側の属性の値が全て出力される。 {{プロパティ名.属性名}} //子コンポーネント側の特定の属性の値が出力される。 </子コンポーネント名> |
さらに、「:default」すらも省略する事が可能です。
1 2 3 4 |
<子コンポーネント名 v-slot="プロパティ名"> {{プロパティ名}} //子コンポーネント側の属性の値が全て出力される。 {{プロパティ名.属性名}} //子コンポーネント側の特定の属性の値が出力される。 </子コンポーネント名> |
#を使ってv-slotの省略記法を使いたい場合は下記のようにします。
1 2 3 4 |
<子コンポーネント名 #default="プロパティ名"> {{プロパティ名}} //子コンポーネント側の属性の値が全て出力される。 {{プロパティ名.属性名}} //子コンポーネント側の特定の属性の値が出力される。 </子コンポーネント名> |
フォールバックコンテンツ(デフォルトのタグ)
slotタグの中に何か書いておくと何も渡されなかった際のデフォルトのタグを設定できます。
この記事へのコメントはありません。