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


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

前置き

あまり見かけない$slotsのご紹介🌟

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

vm.$slots のアクセスは、描画関数によるコンポーネントを書くときに最も便利です。
vm.$slots

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

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

参考:
描画関数とJSX
【Vue.js】コンポーネントのtemplateの書き方まとめ

$slots

vm.$slots
デフォルトとエラー時などで
表示を切り替えたい際に便利です✨
見てもらった方が早いと思います👀

<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文法編: スコープ付きスロットを使おう

描写(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>

NG例①Vue公式をコピペ

描画関数とJSX
こちらの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
こちらを参考にやってみます。
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関数内だけでなく
使用ができて便利ですね🌟