Vue.jsのスロットについて使い方が曖昧だったので、公式ドキュメントから自分なり咀嚼してまとめる。
slotとは
受け取った子コンポーネントに親コンポーネントから要素の受け渡しができる。
子コンポーネント<slot></slot>
の部分に親コンポーネントで渡した要素が入る
<template>
<a href= "https://www.google.com/"
class="nav-link">
<slot></slot>
</a>
</template>
<template>
<div id="app">
<navigationLink>
Googleへのリンク
</navigationLink>
</div>
</template>
結果
もしも <navigationLink>
のテンプレートが 要素を含まない場合、開始タグと終了タグの間にある任意のコンテンツは破棄される。
この場合だと、Googleへのリンクは破棄され、何も描画されなくなる
・スロットには任意のタグや他のコンポーネントを埋め込むことが出来る
<template>
<!--ボタンタグを埋め込み-->
<navigationLink>
<button>Googleへのリンク</button>
</navigationLink>
<!--コンポーネントの埋め込み-->
<navigationLink>
<List />
</navigationLink>
</template>
フォールバックコンテンツ
フォールバックとは、通常使用する方式や系統が正常に機能しなくなったときに、機能や性能を制限したり別の方式や系統に切り替えるなどして、限定的ながら使用可能な状態を維持すること。 また、そのような切り替え手順・動作のこと
参考:IT用語辞典 e-Words
つまり、子コンポーネントのButtonタグの間に何も記述がなかった場合、切り替え手順として<slot>
タグ間に設定してあるSubmitが描画される
<template>
<button type="submit">
<slot>Submit</slot>
</button>
</template>
<template>
<div id="app">
<!--Submitが表示される-->
<Button></Button>
<!--送信が表示される-->
<Button>送信</Button>
</div>
</template>
名前付きスロット
複数のスロットを使う際に、名前を付けて場合分けをする
名前付きスロットを使う場合は<template>
タグで囲い、v-slotで名前をつける
今回は<template v-slot:header>
とする
子コンポーネントでは<slot name="header">
のように指定する
<template>
タグで囲っていない要素は名前なしの<slot>
に入る
<div id="app">
<baseLayout>
<!-- <slot name="header" />に入る -->
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<!-- 名前なしslotに入る -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!-- <slot name="footer" />に入る -->
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</baseLayout>
</div>
<div class="container">
<header>
<!-- 親コンポーネントのv-slot:headerの要素を受け取る -->
<slot name="header" />
</header>
<main>
<!-- 名前を付けない場合はtemplete外の要素を受け取る -->
<slot></slot>
</main>
<footer>
<!-- 親コンポーネントのv-slot:footerの要素を受け取る -->
<slot name="footer"></slot>
</footer>
</div>
名前なしを明示的に指定したい場合は
<template v-slot:default>
のようにdefaultをつける
コンパイルスコープ
このスロットはParent.vue内のdataにアクセス出来る。
navigationLink.vueのスコープにはアクセス出来ない。
<template
<navigationLink>
{{user.lastName}}
</navigationLink>
<!-- 省略 -->
<script>
data(){
return{
user:{lastName:"yamada",firstName:"taro"}
}
}
</script>
スコープ付きスロット
親コンポーネント側から子コンポーネントのデータにアクセスしたい場合<slot>
要素に属性を指定してバインドする
<template>
<span>
<!-- dataのusreをバインドして親コンポーネントからアクセス -->
<slot :user="user">
{{ user.lastName }}
</slot>
</span>
</template>
<script>
export default {
data(){
return {
user:{lastName:"tanaka",firstName:"jiro"}
}
}
}
</script>
<currentUser>
<!-- slotPropsは任意の値 -->
<template v-slot:default="slotProps">
<!-- 子コンポーネントのuserにアクセス -->
{{ slotProps.user.firstName }}
</template>
</currentUser>
<!-- 省略記法 -->
<!-- 名前なしスロットのみの場合コンポーネントタグをスロットのテンプレートとして使うことができる -->
<!-- ただし、名前付きスロットと混在は不可。複数slotがある場合は<template>を使う -->
<currentUser v-slot="slotProps">
{{ slotProps.user.firstName }}
</currentUser>
<!---分割代入を使った記法 -->
<currentUser v-slot="{ user }">
{{ user.firstName }}
</currentUser>
<!---分割代入はプロパティをリネームする事もできる -->
<currentUser v-slot="{ user:person }">
{{ person.firstName }}
</currentUser>
動的なスロット名
スロット名は動的に定義が可能。
例えばdataからスロット名を定義できる
<div>
<slot name="slotName"></slot>
</div>
<baseLayout>
<template v-slot:[dynamicSlotName]>
...
</template>
</baseLayout>
<!-- 省略 -->
<script>
data(){
return{
dynamicSlotName:"slotName"
}
}
</script>
名前付きスロットの省略記法
v-slotは省略があり#で置き換えられる。
例えばv-slot:header
は#header
に書き換えられる
名前なしスロットで省略記法を使いたい場合はdefault
でスロット名を指定する必要がある
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>