【Nuxt.js】$slotsを使ってみよう

🎈 この記事はWP専用です
https://wp.me/pc9NHC-1iY

#前置き
あまり見かけない$slotsのご紹介🌟

$slotsはVue公式の
render関数で使用されています。

> vm.$slots のアクセスは、[描画関数](https://jp.vuejs.org/v2/guide/render-function.html)によるコンポーネントを書くときに最も便利です。
[vm.$slots](https://jp.vuejs.org/v2/api/#vm-slots)

ただrender関数はNuxtでやるのは
結構むずかしいです💥
なのでrender関数を使用しない
実用的な$slotsの使用例をご紹介します。

同時にrender関数については
何をしたい時に使うか、
そしてNG例をご紹介します。

参考:
[描画関数とJSX](https://jp.vuejs.org/v2/guide/render-function.html)
[【Vue.js】コンポーネントのtemplateの書き方まとめ](https://qiita.com/seya/items/93a0055c8fdab62d584f)

#$slots
[vm.$slots](https://jp.vuejs.org/v2/api/#vm-slots)
デフォルトとエラー時などで
表示を切り替えたい際に便利です✨
見てもらった方が早いと思います👀

```TextSlot
<template>
  <span v-if="$slots.default">
    <slot />
  </span>
  <span v-if="$slots.error">
    <slot name="error" />
  </span>
</template>
```

```index.vue
<template>
  <div class="page">
    <TextSlot>
      <template>
        {{ text }}
      </template>
      <template #error>
        {{ textError }}
      </template>
    </TextSlot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      text: '通常テキスト',
      textError: 'エラー時のテキスト',
    }
  ,
}
```

スロットを複数使う場合は
名前付きにしていました。
ただslotの状態によって
表示/非表示をv-ifで
切り替えることはできませんでした💡
それが$slotsを使えばできるんです🍀

⬇️スコープ付きスロットなどは
　こちらをご覧ください👀
[【Nuxt.js】slot文法編: スコープ付きスロットを使おう](https://nuxt.alizlab.com/%e3%80%90nuxt-js%e3%80%91slot%e6%96%87%e6%b3%95%e7%b7%a8-%e3%82%b9%e3%82%b3%e3%83%bc%e3%83%97%e4%bb%98%e3%81%8d%e3%82%b9%e3%83%ad%e3%83%83%e3%83%88%e3%82%92%e4%bd%bf%e3%81%8a%e3%81%86/)

#描写(render)関数
前置きでも書きましたが、
Nuxtでこれを使うのは
結構むずかしいです💥

できること、NG例を
ご紹介します。

公式のコードをNuxtに置き換えます。
levelというpropsによって
h1〜h6のどれを表示させるか…
コードはこうなります。
長いし、slotが重複してしまいます。
これを省略できるのがrender関数です。

```AnchoredHeading.vue
<template>
  <div class="ttl">
    <h1 v-if="level === 1">
      <slot></slot>
    </h1>
    <h2 v-else-if="level === 2">
      <slot></slot>
    </h2>
    <h3 v-else-if="level === 3">
      <slot></slot>
    </h3>
    <h4 v-else-if="level === 4">
      <slot></slot>
    </h4>
    <h5 v-else-if="level === 5">
      <slot></slot>
    </h5>
    <h6 v-else-if="level === 6">
      <slot></slot>
    </h6>
  </div>
</template>

<script>
export default {
  props: {
    level: {
      type: Number,
      required: true,
    },
  },
}
</script>
```

親でlevelを指定
h4を表示させたいので4を指定

```index.vue
<template>
  <div class="page">
    <AnchoredHeading :level="4">levelを指定</AnchoredHeading>
  </div>
</template>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/349a0df0-da4d-ea03-64cc-b64716100ad7.png)

##NG例①Vue公式をコピペ
[描画関数とJSX](https://jp.vuejs.org/v2/guide/render-function.html)
こちらのrender関数をコピペしても
Nuxtでは動きません。

```AnchoredHeading.vue
<template>
  <div class="ttl">
  </div>
</template>

<script>
export default {
  props: {
    level: {
      type: Number,
      required: true,
    },
  },
  render: function (createElement) {
    return createElement(
      'h' + this.level,   // タグ名
      this.$slots.default // 子の配列
    )
  },
}
</script>
```

##NG例②
[Nuxt render function for a string of HTML that contains Vue components](https://stackoverflow.com/questions/56013561/nuxt-render-function-for-a-string-of-html-that-contains-vue-components)
こちらを参考にやってみます。
templateなので
hタグの入れ子にslotは入らなそうなのと、
そもそも動きません。

```AnchoredHeading.vue
<template>
  <div class="ttl">
  </div>
</template>
<script>
export default {
  props: {
    level: {
      type: Number,
      required: true,
    },
  },
  render(h, context) {
    return h({ template: `h${this.level}, ${this.$slots.default}` })
  },
}
</script>
```

じゃあ使うためにはどうするか、
今のところJSXを
使うしかなさそうです。

#まとめ
$slotsはrender関数内だけでなく
使用ができて便利ですね🌟