Vue slotの使い方まとめ

# slot(スロットコンテンツ)とは
> [公式](https://jp.vuejs.org/v2/guide/components-slots.html)
> Vue には Web Components spec draft にヒントを得たコンテンツ配信 API が実装されており、 <slot> 要素をコンテンツ配信の受け渡し口として利用します。

## 基本編

### slotタグのみ定義
タグ配下に記載したものが、スロット部分に設定される

```vue:navigationLink.vue
<template>
  <a v-bind:href="url" class="nav-link">
    <slot></slot>
  </a>
</template>

<script>
export default {
  props: ["url"]
};
</script>
```

```vue:App.vue
<template>
  <div>
    <navigationLink url="/profile">
      Your Profile
    </navigationLink>
  </div>
</template>

⇒
    <a href="/profile" class="nav-link">
      Your Profile
    </a>
```

### slotタグのみ定義と同じ意味
slotのnameにdefaultを設定する

```vue:navigationLink.vue
<template>
  <a v-bind:href="url" class="nav-link">
    <slot name="default"></slot>
  </a>
</template>

<script>
export default {
  props: ["url"]
};
</script>
```

### slotを複数定義(name指定)
name指定することで、コンポーネント使用時にどこを置き換えるか指定できる
- 「slot name="XXX"」と「v-slot:XXX」が対応
- 「v-slot:XXX」が定義されていない場合、フォールバックし「slot name="XXX"」の内容が表示される

```vue:slotComp.vue
<template>
  <div>
    <slot name="header">Header</slot>

    <slot></slot>

    <slot name="footer">Footer</slot>
  </div>
</template>

```

```vue:App.vue
<template>
  <div>
    <slotComp>
      <template v-slot:header>
        <div>Title</div>
      </template>
      body
    </slotComp>
  </div>
</template>

⇒
    <div>
      <div>Title</div>
      body Footer
    </div>
```

### 省略記法
- 「v-slot:header」===「#header」

```vue:App.vue
<template>
  <div>
    <slotComp>
      <template #header>
        <div>Title</div>
      </template>
      body
      <template #footer>
        <div>footTitle</div>
      </template>
    </slotComp>
  </div>
</template>
```
## 応用編
### slotコンポーネントのデータを利用する
- slotにbindすることで利用側で参照可能となる
⇒ (要素にバインドされた属性は、スロットプロパティと呼ばれる)

```vue:slotComp.vue
<template>
  <div>
    <slot name="header">Header</slot>

    <slot name="main" :user="user"></slot>

    <slot name="footer">Footer</slot>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      user: {
        id: "user_id",
        name: "user_name"
      }
    };
  }
};
</script>
```

```vue:App.vue
<template>
    <slotComp>
      <template #header>
        <div>Title</div>
      </template>

      <template v-slot:main="{ user }">
        <div>{{ user.id }}</div>
        <div>{{ user.name }}</div>
      </template>

      <template #footer>
        <div>footTitle</div>
      </template>
    </slotComp>
</template>

⇒
    <div>
      <div>Title</div>
      <div>user_id</div>
      <div>user_name</div>
      <div>footTitle</div>
    </div>
```

### 動的設定
- 「v-slot:[XXX]」で動的に「slot」を指定できる

```vue:slotComp.vue
<template>
  <span>
    <slot :categories="categories"></slot>
    <slot name="new_categories" :categories="newCategories"></slot>
  </span>
</template>

<script>
export default {
  data() {
    return {
      categories: ["Dart", "Flutter", "Vue.js"],
      newCategories: ["Mobile", "Cross Platform", "Frontend Tech"]
    };
  }
};
</script>
```

```vue:App.vue
<template>
  <div>
    <slotComp v-slot:[collection]="{ categories }">
      <ul>
        <li v-for="category in categories" :key="category">
          {{ category }}
        </li>
      </ul>
    </slotComp>
    <button @click="changeCollection">Change</button>
  </div>
</template>

<script>
import slotComp from "./components/slotComp";

export default {
  components: { slotComp },
  data: function() {
    return {
      collection: "default"
    };
  },
  methods: {
    changeCollection() {
      this.collection =
        this.collection === "default" ? "new_categories" : "default";
    }
  }
};
</script>
```