親コンポーネントから子コンポーネントに、htmlごとデータを送る。
<template>
<div>
<likeHeader>
<h1>{{ word }}</h1>
</likeHeader>
</div>
</template>
<script>
import likeHeader from "./components/likeHeader.vue";
export default {
name: "App",
data() {
return {
word: "スロットを通じて送られました",
};
},
components: {
likeHeader,
},
};
</script>
<template>
<div>
<slot></slot>
</div>
</template>
<script>
</script>
親コンポーネントのカスタムタグで囲まれた部分が、子コンポーネントのslotタグで囲まれた部分に送られる。
slotのスコープについて
実際に記載しているファイルにスコープが発生している。例えば下記のように、親コンポーネントのカスタムタグに子コンポーネント定義しているchildを渡しても、読み込むことはできない。
<template>
<div>
<likeHeader>
<h1>{{ child }}</h1>
</likeHeader>
</div>
</template>
<script>
import likeHeader from "./components/likeHeader.vue";
export default {
components: {
likeHeader,
},
};
</script>
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
child: "子で定義",
};
},
};
</script>
結果、未定義エラーとなる。
[Vue warn]: Property or method "child" is not defined on the instance
but referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components,
by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
ただし、styleタグについては、親コンポーネント子コンポーネントどちらに定義しても反映される。また、親と子に同一の定義があった場合は、
<style>
h1 {
color: red;
}
</style>
<style>
h1 {
color: blue;
}
</style>
親コンポーネントの定義が優先される。
slotにデフォルトの値を設定する。
<slot>デフォルト</slot>
スロットタグの中に、デフォルトで表示したい値を設定する。
<template>
<div>
<likeHeader> </likeHeader>
</div>
</template>
親コンポーネントのカスタムタグに値を入れなかった場合は、デフォルトの値が表示される。
逆に、カスタムタグの間に値を入れた場合は、デフォルトの値は表示されない。
<slot>デフォルト</slot>
スロットタグの中に、デフォルトで表示したい値を設定する。
<template>
<div>
<likeHeader>デフォルトじゃない</likeHeader>
</div>
</template>
名前付きslotで表示を分ける。
<template>
<div>
<likeHeader>
<template v-slot:title>タイトル</template>
<template v-slot:content>コンテンツ</template>
</likeHeader>
</div>
</template>
<script>
import likeHeader from "./components/likeHeader.vue";
export default {
components: {
likeHeader,
},
};
</script>
<template>
<div>
<slot name="title"></slot>
<slot name="content"></slot>
</div>
</template>
親コンポーネントのカスタムタグ内にtemplateタグを設定し、v-slotディレクティブを設定し、任意の引数(title, content)を与える。
子コンポーネントで、slotタグに指定した任意の引数と一致する値(title, content)をname属性に与える。
デフォルトslot
v-slotディレクティブを指定したtemplateタブで囲われいない部分は、全て子テンプレートのデフォルトslot(name属性が与えられていないslot)に集約されて表示される。
<template>
<div>
<likeHeader>
<p>1</p>
<template v-slot:title>タイトル</template>
<p>2</p>
<template v-slot:content>コンテンツ</template>
<p>3</p>
</likeHeader>
</div>
</template>
<script>
import likeHeader from "./components/likeHeader.vue";
export default {
components: {
likeHeader,
},
};
</script>
<template>
<div>
<slot name="title"></slot>
<slot></slot>
<slot name="content"></slot>
</div>
</template>
この挙動は、親コンポーネント側で、templateタグに囲まれていいない部分を、新たにtemplateタグに集めて、そのtemplateタグにv-slot:default というディレクティブを与えている。
そして、子コンポーネントのデフォルトslotにname="default"を与えている。つまり下記のような処理をvueが自動で行っている。
<template>
<div>
<likeHeader>
<template v-slot:default>
<p>1</p>
<p>2</p>
<p>3</p>
</template>
<template v-slot:title>タイトル</template>
<template v-slot:content>コンテンツ</template>
</likeHeader>
</div>
</template>
<script>
import likeHeader from "./components/likeHeader.vue";
export default {
components: {
likeHeader,
},
};
</script>
<template>
<div>
<slot name="title"></slot>
<slot name="default"></slot>
<slot name="content"></slot>
</div>
</template>
なお、soltに送る際は、templateタグでないとエラーとなる。(divタグとかではダメ)
slotを用いて子コンポーネントから親コンポーネントにデーターを渡す。
slotにカスタム属性をバインドすることにより、親子コンポーネントのv-slotの仮引数に格納することができる。!
なお、v-slot:は # に置き換えることができる。