Vue.js Slotの使い方

Vue.jsのスロットについて使い方が曖昧だったので、公式ドキュメントから自分なり咀嚼してまとめる。

##slotとは

受け取った子コンポーネントに親コンポーネントから要素の受け渡しができる。

子コンポーネント<`slot></slot>`の部分に親コンポーネントで渡した要素が入る


```navigationLink.vue
<template>
 <a href= "https://www.google.com/"
  class="nav-link">
  <slot></slot>
</a>
</template>

```

```Parent.vue
<template>
  <div id="app">
    <navigationLink>
      Googleへのリンク
    </navigationLink>
  </div>
</template>

```
結果
[![Image from Gyazo](https://i.gyazo.com/880a6cb9e17111dfbc667f35c2835e30.png)](https://gyazo.com/880a6cb9e17111dfbc667f35c2835e30)
もしも `<navigationLink>` のテンプレートが <slot> 要素を含まない場合、開始タグと終了タグの間にある任意のコンテンツは破棄される。
この場合だと、Googleへのリンクは破棄され、何も描画されなくなる



・スロットには任意のタグや他のコンポーネントを埋め込むことが出来る

```Parent.vue
<template>
 <!--ボタンタグを埋め込み-->
 <navigationLink>
  <button>Googleへのリンク</button>
 </navigationLink>

<!--コンポーネントの埋め込み-->
 <navigationLink>
  <List />
 </navigationLink>
</template>
```

## フォールバックコンテンツ

フォールバックとは、通常使用する方式や系統が正常に機能しなくなったときに、機能や性能を制限したり別の方式や系統に切り替えるなどして、限定的ながら使用可能な状態を維持すること。 また、そのような切り替え手順・動作のこと
参考:IT用語辞典 e-Words

つまり、子コンポーネントのButtonタグの間に何も記述がなかった場合、切り替え手順として`<slot>`タグ間に設定してあるSubmitが描画される


```Button.vue
<template>
<button type="submit">
  <slot>Submit</slot>
</button>
</template>
```
```Parent.vue
<template>
  <div id="app">
　<!--Submitが表示される-->
  <Button></Button>
  <!--送信が表示される-->
  <Button>送信</Button>
  </div>
</template>
```

## 名前付きスロット
複数のスロットを使う際に、名前を付けて場合分けをする
名前付きスロットを使う場合は`<template>`タグで囲い、v-slotで名前をつける
今回は`<template v-slot:header>`とする
子コンポーネントでは`<slot name="header">`のように指定する
`<template>`タグで囲っていない要素は名前なしの`<slot>`に入る


```Parent.vue
 <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>
```

```baseLayout.vue
 <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のスコープにはアクセス出来ない。


```Parent.vue
<template
 <navigationLink>
   {{user.lastName}}
 </navigationLink>

<!-- 省略 -->
<script>
data(){
    return{
      user:{lastName:"yamada",firstName:"taro"}
    }
  }
</script>
```


## スコープ付きスロット
親コンポーネント側から子コンポーネントのデータにアクセスしたい場合`<slot>` 要素に属性を指定してバインドする

```currentUser.vue
<template>
<span>
  <!-- dataのusreをバインドして親コンポーネントからアクセス -->
  <slot :user="user">
    {{ user.lastName }}
  </slot>
</span>
</template>
<script>
export default {
  data(){
    return {
      user:{lastName:"tanaka",firstName:"jiro"}
    }
  }
}
</script>
```
```Parent.vue
 <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からスロット名を定義できる

```baseLayout.vue
<div>
  <slot name="slotName"></slot>
</div>
```

```Parent.vue
<baseLayout> 
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</baseLayout>
<!-- 省略 -->
<script>
 data(){
    return{
      dynamicSlotName:"slotName"
    }
  }
</script>
```

## 名前付きスロットの省略記法
v-slotは省略があり#で置き換えられる。
例えば`v-slot:header`は`#header`に書き換えられる
名前なしスロットで省略記法を使いたい場合は`default`でスロット名を指定する必要がある

```Parent.vue
<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>
```

参考: https://vuejs.org/v2/guide/components-slots.html