私はVue.jsを勉強して間もない。スロットを学習して、名前付きスロットで遊んで。そして躓いた。参考にしていた書籍では slot属性 を使い、https://jp.vuejs.org/では v-slotディレクティブ を使っていたためだった。しかも、slot属性は 非推奨(ver:2.6~) となってしまっていた。
サンプル
名前付きスロットについて slot属性(slot="XXX"
)を利用したパターンとv-slotディレクティブ(<template v-slot:XXX>
)を使ったパターンを残す。
<head>
<script src="https://unpkg.com/vue@2.6.0"></script>
</head>
<body>
<div id="slot-test">
<!-- パターン1 -->
<h1>v-slotの確認(slot属性)</h1>
<com0>
<strong>ABCDE</strong>
<strong slot="slot2">VWXYZ</strong>
</com0>
<!-- パターン2 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
<strong>ABCDE</strong>
<template v-slot:slot2>
<strong>VWXYZ</strong>
</template>
</com0>
</div>
<script>
Vue.component('com0',{
data: function(){
return {};
},
template: `
<div>
<p>hogehoge <slot></slot> hogehoge</p>
<p>piyopiyo <slot name="slot2"></slot> piyopiyo
</div>
`
})
new Vue({el:'#slot-test'})
</script>
</body>
以上。1ソースに2パターン組み込んだので読みづらいかもしれない。
2パターンのいずれもコンポーネント com0 を利用している。 com0の template には2つのslotが用意されている。
template: `
<div>
<p>hogehoge <slot></slot> hogehoge</p>
<p>piyopiyo <slot name="slot2"></slot> piyopiyo
</div>
`
片方のslotには name属性 を設けている(<slot name="slot2">..</slot>
)。slotに名前をつけることでコンテンツをどのslotに配信するか指定することが出来るようになる。そして、その指定方法が今回の注目ポイントとなる。また、注意だが templateは一つのroot要素でなければならない らしい。今回のtemplateの場合はdiv要素が一つのrootにあたる。
パターン1
参考書籍にあった slot属性 パターン。
slot属性によって、配信先を指定している。配信先が指定されている場合は該当するslotに配信され、指定がない場合は無名のslotに配信される。指定した名前に該当がないものは配信されない。
<!-- パターン1 -->
<h1>v-slotの確認(slot属性)</h1>
<com0>
<strong>ABCDE</strong>
<strong slot="slot2">VWXYZ</strong>
</com0>
パターン2
今後使うべき v-slotディレクティブ パターン。ここで登場するのが<template>
。<template>で配信するコンテンツを囲い、v-slotディレクティブで配信先を指定すれば良い。
<!-- パターン2 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
<strong>ABCDE</strong>
<template v-slot:slot2>
<strong>VWXYZ</strong>
</template>
</com0>
出力結果
パターン1もパターン2も同じ結果が得られる。
<div id="slot-test">
<!-- パターン1 -->
<h1>v-slotの確認(slot属性)</h1>
<div>
<p>hogehoge <strong>ABCDE</strong> hogehoge</p>
<p>piyopiyo <strong>VWXYZ</strong> piyopiyo</p>
</div>
<!-- パターン2 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<div>
<p>hogehoge <strong>ABCDE</strong> hogehoge</p>
<p>piyopiyo <strong>VWXYZ</strong> piyopiyo</p>
</div>
</div>
さらに
気付いた点をまとめておく
パターン1とパターン2をもっと丁寧に
パターン1とパターン2を丁寧に書き直し、パターン1改とパターン2改を書く。
<!-- パターン1改 -->
<h1>v-slotの確認(slot属性)</h1>
<com0>
<strong slot="default">ABCDE</strong>
<strong slot="slot2">VWXYZ</strong>
</com0>
<!-- パターン2改 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
<template v-slot:default>
<strong>ABCDE</strong>
</template>
<template v-slot:slot2>
<strong>VWXYZ</strong>
</template>
</com0>
具体的には配信先の指定がないものに配信先を明記しただけ。同様にコンポーネントも書き換える。
<script>
Vue.component('com0',{
data: function(){
return {};
},
template: `
<div>
<p>hogehoge <slot name="default"></slot> hogehoge</p>
<p>piyopiyo <slot name="slot2"></slot> piyopiyo
</div>
`
})
new Vue({el:'#slot-test'})
</script>
コンポーネントは 名前がつけられていないslot に default という名前をつけた。
これは資料を読んでいれば書かれていることであったが、暗黙的にdefaultという名前がつけられるとされている。文献では敢えて配信先にdefaultを明示することは少ないが、改めて書き加えてみると単純な話だったと思う。
パターン1について言えば、 配信先の指定がないものはslot="default"
が付加されていると考えればよい。パターン2について言えば<template>に囲われていない要素は、<template v-slot:default>
に囲われていると考えれば良い。そう理解すれば、全てのコンテンツに配信先が明示されていると考えられ迷子になることが無い。
繰り返し確認になるがソースコードを残す。
<!-- パターン2確認 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
<strong>ABCDE</strong>
FGHIJ
<template v-slot:slot2>
<strong>VWXYZ</strong>
</template>
KLMNO
</com0>
上記ソースコードは次の通り理解する。
<!-- パターン2確認 -->
<!-- <template>で囲われていないコンテンツは
<template v-slot:default></template>
で囲われている。<slot name="default"></slot>に配信される。
-->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
<template v-slot:default>
<strong>ABCDE</strong>
</template>
<template v-slot:default>
FGHIJ
</template>
<template v-slot:slot2>
<strong>VWXYZ</strong>
</template>
<template v-slot:default>
KLMNO
</template>
</com0>
<template>>囲われていないコンテンツは全て<template v-slot:default></template>
で囲われている。これらは<slot name="default"></slot>
に配信される。ただし、name="default"
は省略されることがおおい。
ただし、注意であるが勘違いしてはいけないことがある。<slot name="default"></slot>
は必ずしも存在しているわけで無いという点である。例えば、コンポーネントのtemplateのslotに全て名前がつかれている場合はデフォルトのslotが存在しないことになる。この場合は配信先が指定されなかったコンテンツは配信先が無いため配信されない。
<script>
Vue.component('com0',{
data: function(){
return {};
},
template: `
<div>
<p>hogehoge <slot name="slot1"></slot> hogehoge</p>
<p>piyopiyo <slot name="slot2"></slot> piyopiyo
</div>
`
})
new Vue({el:'#slot-test'})
</script>
なぜか混乱した
v-slotディレクティブを理解するのに混乱した。それは slot属性による指定方式 を <template>+v-slotディレクティブの組み合わせによる指定方式 に変換できなかったことが考えられる。また、両パターンを並べてあるソースコードが見つけられなかったことで余計に悩んでしまった。