[Vue.js]slotを理解したい

こんにちは、basyouです。(@basyuokajiki)

Vue.jsの学習を進めているのですが、slotで「ん?」となる点が多々あったので備忘録としてまとめていきます。

## slotとは何者か

v-slotとは、親のコンポーネント から子コンポーネントにテンプレートを挿入できる機能のこと。


## slotの挙動

vueプロジェクトがあったとして、このようなコードがあったとします。

Hoge.Vue(親コンポーネント)

<template>
  <div>
    <Fuga>
      <h2>こんにちは</h2>
      <p>{{ name }}</p>
    </Fuga>
  </div>
</template>
<script>
import Fuga from './components/Fuga'
export default {
  components: {
   Fuga
  },
  data() {
    return {
      name: 'ほげほげさん'
    }
  }
}
</script>

Fuga.vue(子コンポーネント)

<template>
  <div>
    <slot></slot>
  </div>
</template>
<script>
</script>

このように記述すると、子コンポーネント の<slot></slot>に、親コンポーネントの

<h2>こんにちは</h2>
<p>{{ name }}</p>

が挿入されます。
これがv-slotの基本的な挙動です。

こんにちは
ほげほげさん

と表示されるハズです。

### slotのデフォルト値

slotにはデフォルト値を指定できます。

親コンポーネント

<template>
  <div>
    <Fuga>
      <!-- この中に何も入れない --->
    </Fuga>
  </div>
</template>
<script>
import Fuga from './components/Fuga'
export default {
  components: {
   Fuga
  },
  data() {
    return {
      name: 'ほげほげさん'
    }
  }
}
</script>

子コンポーネント

<template>
  <div>
    <slot>なにもないよ!!!</slot>
  </div>
</template>
<script>
</script>

親コンポーネントにある<Fuga></Fuga>の間になにもないと、
子コンポーネントないの<slot></slot>内にあるものが反映されます。

表示結果

なにもないよ!!!


### 複数のslot

1つのテンプレート内に複数のslotを置くことが可能です。

親コンポーネント

<template>
  <div>
    <Fuga>
      <p>いらっしゃいませ</p>
    </Fuga>
  </div>
</template>

子コンポーネント

<template>
  <div>
    <slot></slot>
    <slot></slot>
    <slot></slot>
  </div>
</template>

結果

いらっしゃいませ
いらっしゃいませ
いらっしゃいませ

slotを3回使用したので、このようにブックオフの店員のような表示がされます。


### v-slotを使用して名前付きのslotを使う

上記のただ繰り返すだけのslotはあまり使い勝手がよくありません。
ということでslotに名前をつけて、別々で管理できるようにします。

<template>
  <div>
    <Fuga>
      <h2>あいさつ</h2>
      <p>いらっしゃいませ</p>
    </Fuga>
  </div>
</template>

<Fuga></Fuga>にある要素を名前付きで管理します。

<template>
  <div>
    <Fuga>
      <template v-slot:greeting>
        <h2>あいさつ</h2
      </template>
      <template v-slot:message> 
        <p>いらっしゃいませ</p>
      </template>
    </Fuga>
  </div>
</template>

このように<template>タグで囲ってあげて、v-slotディレクティブを使用します。

子コンポーネントは以下のように記述します。

<template>
  <div>
   <slot name="greeting"></slot>
   <slot name="message"></slot>
  </div>
</template>

nameで紐づけてあげるイメージですね!

結果

あいさつ
いらっしゃいませ


## 子から親にデータを渡すslot(スコープ付きスロット)

どうしても子にあるデータを親で使いたいという時に使います。

<template>
  <div>
   <slot name="title" v-bind:user="user"></slot>
  </div>
</template>
<script>
export default {
  data() {
    return {
      user: {
        name: 'ほげほげさん',
        age: '24'
    }
  }
}
</script>

<template>
  <div>
    <Fuga>
      <template v-slot:title="slotProps">
        <h2>こんにちは</h2
        <p>{{ slotProps }}</p>
      </template>
    </Fuga>
  </div>
</template>

多分意味わからないと思うので、1つ1つ手順を解説します。

①子コンポーネントの中にある<slot>タグの中に以下の記述を追加します。

v-bind:〇〇="user"
※〇〇は好きな名前
※userはscriptタグ内にある参照したいdata
※もちろん省略記法 :〇〇="user としても大丈夫


②親コンポーネントの<template>タグ内にある「v-slot:title」を以下のように変えてあげる

v-slot:△△="○○"
※今回はslotでnameを指定しているので、△△はtitleだがデフォルトslotしかない場合は暗黙的に、v-slot:default となる
※〇〇は好きな名前
子コンポーネントのV-bindで指定した○○とは同じじゃなくて良い

これで準備完了です。
このようにすることで以下のように表示されます。

こんにちは
{"user":{"name": "ほげほげさん", "age": "24"}}

子コンポーネントのデータを取り出せたことがわかると思います。

次に親をこのように書き換えてみます。

<template>
  <div>
    <Fuga>
      <template v-slot:title="slotProps">
        <h2>こんにちは</h2
        <p>{{ slotProps.user.name }}</p>
        <p>{{ slotProps.user.age }}</p>
      </template>
    </Fuga>
  </div>
</template>

結果

こんにちは
ほげほげさん
24


#### いったい何が起こったのか?

多分僕が言語化するより、他の記事で紹介されているものを参考にされていると思います。

Vue.js中級編!?「スコープ付きスロット」を理解しよう
vue.jsのSlotからScoped Slotまでを理解しよう
公式ページ


## 今回はここまで!

とりあえずslotについて基本のきぐらいはまとめれたと思います。
スコープ付きスロットに関してはもうちょっと理解してから情報をまとめます。

間違いがあったらすいません...!

では今回はこの辺で。


いいなと思ったら応援しよう!