Vue slot編

## はじめに
前回のコンポーネント編に引き続き、今回はスロットについてまとめます。間違いがあればご指摘お願いします。

#### スロットとは？
親コンポーネントから子コンポーネントにデータを送信する方法として子コンポーネントでpropsオプションを定義して親コンポーネントからのデータの受け口を作るというものがありました。確かにデータを送るのにはpropsオプションは適しているのかもしれませんが、htmlを送りたいときにはそうではありません。親から子にhtmlを送りたいときに使えるのがスロットというものです。

#### 簡単なスロット
簡単なスロットの例を示します。

```vue:App.vue
<template>
  <div>
    <Slot>
      This is a simple slot.
    </Slot>
  </div>
</template>
```

```vue:Slot.vue
<template>
  <slot></slot>
</template>
```

![スクリーンショット 2020-12-01 15.07.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574301/ec4b188c-9cd8-eb6a-f49d-cc3a025bf66b.png)

このように表示されました。次に名前付きスロットについて見ていきましょう。


#### 名前付きスロット
先ほどは簡単なスロットの例としてThis is a simple slot.と表示する実装をしましたが、htmlを割り当てて表示したい時はどのようにすれば良いのでしょうか。
例えばこのようなコードがあったとします。

```vue:App.vue
<template>
  <Slot>
    <header>
        This is a header.
      </header>
      <main>
        This is a main.
      </main>
      <footer>
        This is a footer.
      </footer>
  </Slot>
</template>
```

```vue:Slot.vue
<template>
  <slot></slot>
  <slot></slot>
  <slot></slot>
</template>
```

![スクリーンショット 2020-12-01 15.23.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574301/688786b4-30c8-8fdd-4792-c6024d94580e.png)


これだと子コンポーネントのslotそれぞれにヘッダー、メイン、フッターの全てが描画されることになります。
一つ目のスロットにヘッダー、二つ目のスロットにメイン、三つ目のスロットにフッターを割り当てたい時、以下のような名前付きスロットを用いることによって、実装可能になります。

```vue:App.vue
<template>
  <Slot>
    <template v-slot:header>
      This is a header.
    </template>
    <template v-slot:main>
      This is a main.
    </template>
    <template v-slot:footer>
      This is a footer.
    </template>
  </Slot>
</template>
```

```vue:Slot.vue
<template>
  <div>
    <header>
       <slot name="header"></slot>
    </header>
    <main>
       <slot name="main"></slot>
    </main>
    <footer>
       <slot name="footer"></slot>
    </footer>
  </div>
</template>
```

![スクリーンショット 2020-12-01 15.30.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574301/670eb2eb-0e93-c7f3-c03d-b1219d0d6c1a.png)

親コンポーネントの方でv-slotディレクティブを使用してスロットに任意の名前をつけ、子コンポーネントの方ではslotタグにname属性をつけて先ほど定義したスロット名と対応させると上の画像のようにヘッダー、メイン、フッターでそれぞれ別のスロットで表示することができる。


#### スコープ付きスロット

子コンポーネントの中でのみアクセス可能なデータに親コンポーネントからアクセスできると便利なケースがあります。そのときに重宝するのが、スコープ付きスロットです。
先程のコードから少し編集を加えて、

```vue:App.vue
<template>
  <Slot>
    <template v-slot:header>
      This is a header.
    </template>
    <template v-slot:main="slotProps">
      This is a main.
      My name is {{ slotProps.user.firstName }} {{ slotProps.user.lastName }}.
    </template>
    <template v-slot:footer>
      This is a footer.
    </template>
  </Slot>
</template>
```

```vue:Slot.vue
<template>
  <div>
    <header>
       <slot name="header"></slot>
    </header>
    <main>
       <slot name="main" v-bind:user="user"></slot>
    </main>
    <footer>
       <slot name="footer"></slot>
    </footer>
  </div>
</template>

<script>
export default {
    data: function() {
        return {
            user: {
                firstName: "Mesut",
                lastName: "Ozil"
            }
        }
    }
}
</script>
```

![スクリーンショット 2020-12-02 14.25.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574301/9108cc19-edf9-f6db-8f2d-f716d9332ec2.png)


とすることで子コンポーネントで定義したデータに親コンポーネントでアクセスすることが出来ます。
slot要素をv-bindでバインディングしたものをスロットプロパティと言い、親コンポーネントのv-slot名に値を指定することでスロットプロパティを受け取ることが出来ます。今回、slotPropsとしていますが、任意の名前で構いません。