Vue.jsで名前付きスロットslot属性からv-slotディレクティブが推奨になったのでメモ


私はVue.jsを勉強して間もない。スロットを学習して、名前付きスロットで遊んで。そして躓いた。参考にしていた書籍では **slot属性** を使い、[https://jp.vuejs.org/](https://jp.vuejs.org/v2/guide/components-slots.html#%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88)では **v-slotディレクティブ** を使っていたためだった。しかも、slot属性は **非推奨(ver:2.6~)** となってしまっていた。



#サンプル
名前付きスロットについて slot属性(`slot="XXX"`)を利用したパターンとv-slotディレクティブ(`<template v-slot:XXX>`)を使ったパターンを残す。

```vue:sample00

<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が用意されている。

```vue:com0のtemplate

  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に配信される。指定した名前に該当がないものは配信されない。

```vue:Pattern1

<!-- パターン1 -->
<h1>v-slotの確認(slot属性)</h1>
<com0>
  <strong>ABCDE</strong>
  <strong slot="slot2">VWXYZ</strong>
</com0>
    
```

##パターン2
今後使うべき **v-slotディレクティブ** パターン。ここで登場するのが`<template>`。&lt;template&gt;で配信するコンテンツを囲い、v-slotディレクティブで配信先を指定すれば良い。

```vue:Pattern2

<!-- パターン2 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
  <strong>ABCDE</strong>
  <template v-slot:slot2>
    <strong>VWXYZ</strong>
  </template>
</com0>
    
```


#出力結果
パターン1もパターン2も同じ結果が得られる。

```html:output

<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改を書く。

```vue:Pattern1改

<!-- パターン1改 -->
<h1>v-slotの確認(slot属性)</h1>
<com0>
  <strong slot="default">ABCDE</strong>
  <strong slot="slot2">VWXYZ</strong>
</com0>
    
```

```vue:Pattern2改

<!-- パターン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>
    
```

具体的には配信先の指定がないものに配信先を明記しただけ。同様にコンポーネントも書き換える。

```vue:コンポーネント改

  <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について言えば&lt;template&gt;に囲われていない要素は、`<template v-slot:default>`に囲われていると考えれば良い。そう理解すれば、全てのコンテンツに配信先が明示されていると考えられ迷子になることが無い。

繰り返し確認になるがソースコードを残す。

```vue:Pattern2確認
<!-- パターン2確認 -->
<h1>v-slotの確認(v-slotディレクティブ)</h1>
<com0>
  <strong>ABCDE</strong>
  FGHIJ
  <template v-slot:slot2>
    <strong>VWXYZ</strong>
  </template>
  KLMNO
</com0>
    
```

上記ソースコードは次の通り理解する。

```vue:Pattern2確認
<!-- パターン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>
    
```

&lt;template>&gt;囲われていないコンテンツは全て`<template v-slot:default></template>`で囲われている。これらは`<slot name="default"></slot>`に配信される。ただし、`name="default"`は省略されることがおおい。

ただし、注意であるが勘違いしてはいけないことがある。`<slot name="default"></slot>`は必ずしも存在しているわけで無いという点である。例えば、コンポーネントのtemplateのslotに全て名前がつかれている場合はデフォルトのslotが存在しないことになる。この場合は配信先が指定されなかったコンテンツは配信先が無いため配信されない。

```vue:コンポーネント(全てのslotに名前がついている場合。name="default"が存在しない。)

  <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属性による指定方式** を **&lt;template&gt;+v-slotディレクティブの組み合わせによる指定方式** に変換できなかったことが考えられる。また、両パターンを並べてあるソースコードが見つけられなかったことで余計に悩んでしまった。

##「暗黙的に『default』」を理解する
「[nameの無い&lt;slot&gt;要素は、 **暗黙的に『default』** という名前を持ちます。](https://jp.vuejs.org/v2/guide/components-slots.html#%E9%9D%9E%E6%8E%A8%E5%A5%A8%E3%81%AE%E6%A7%8B%E6%96%87)」が大切。