slot…Vue2をやってた時に、なんかわかりにくいなぁ…とずっと思ってました。
で、Reactやってから見てみたら「あ、これComponentのchildrenなんだわ」ってわかってスゲー腑に落ちた。
ただ、Vueの場合はそのchildrenの要素に名前を付けられるのが便利といえば便利かな…?
ということで、いろいろと試して「あ、こういうこと」ってわかったのでまとめる。slotってその場所にカードを差し込む差込口みたいなイメージなんだけど、名称としてはReactみたいにComponentのchildrenの方がすっとくるかな。Reactの場合は、Propsに付属しているものだしそれがまた「Componentに渡すもの」ってイメージがついて直良し。
slotの感覚をつかむために考えたこと
slotは「親」とか「子」の感覚で見ない方がいい
「親」とか「子」ってわかりやすいようでわかりにくい。たとえば、この場合
<template> <Child> <div>このDIV要素は親?子?</div> </Child> </template>
<template> <p>このP要素は親?子?</p> </template>
page.vueのDIV要素は、Childコンポーネントから見ると「子」なわけですよ。
だけど、Childコンポーネントは、page.vueの「子」であって、DIV要素はChildコンポーネントの「親」であるpage.vueにあるから
あれ?DIV要素ってChildコンポーネントの親なんじゃね?
とかいう感覚に囚われていた。てかさー、ChildコンポーネントってDIV要素からすると親なのに「Child」っておかしくない?
っつーことで、「親」とか「子」っていうの禁止。
単純にslotってコンポーネントで囲った中身なんすよ。
それだけだった…。
名前付きslotって便利(?)なのだけど、それがますますわかりにくくしてる気がする。
コンポーネントの中にあれば、どこに書いてもいいし。ある意味HTML構造を無視しちゃってるから不穏な感じがするんだよね。名前付きslot
NuxtのLayoutで使うslotはまた特殊な感じがする
NuxtのLayoutのslotはComponentの中身を移譲するという意味では同じなんだけど、ラップしている(HTML構造でいえば親になる)部分にslotを使っているのがとても違和感を感じさせる。
サンプル
図解するとこんな感じ。
<template> <ul class="global-menu"> <slot name="menu"> <li>初期メニュー</li> </slot> <slot /> </ul> </template>
<script setup> definePageMeta({ layout: false }) import Banner from "../components/Banner.vue" import Subcontent from "../components/Subcontent.vue" </script> <template> <NuxtLayout name="custom"> <template #menu> <li>メニュー1</li> <li>メニュー2</li> </template> <div> <p>メインとなるコンテンツ</p> <Subcontent> <h3>フルーツ</h3> <ol> <li>バナナ</li> <li>リンゴ</li> <li>メロン</li> </ol> </Subcontent> </div> <Banner> <img src="~/assets/img/banner.png" /> <template #caption>赤バナー</template> </Banner> </NuxtLayout> </template> <style> img { width: 120px; } </style>
<template> <h2>サブコンテンツ:一覧</h2> <slot /> </template>
<template> <slot><img src="~/assets/img/banner_default.png"/></slot> <div> Caption:<slot name="caption"/> </div> </template>
出力されてるHTML