v-slotの使い方が知りたい。
早くGithub Actionsを実装して脳死デプロイができるようになりたいです。
今回は先人PFによく出てくるv-slotについて学習していきたいと思います。
v-slotとは
また親子間の値のやり取りに関するディレクティブが出現してきた。親⇨子というこは、propsと同じなのかな?
propsとの違い
propsは基本的に値を渡すのに対して、slotでは描画内容を渡します。
(https://greko-engineer.hateblo.jp/entry/2019/11/30/195237)
値だけでは無く、タグそのものも渡すことができるってわけかな。
どんな旨みがあるの?
「この部分に、こういう役割のものを表示したい。けれど、どのように表示するかは、このコンポーネントを使う側で決めてほしい」時に旨みがでる。
ユーザーのログイン状態に合わせてヘッダーの状態を変えるときに使える。
例えばv-ifを使ってアクションの状態に応じてボタンの状態を変えたい場合は、下記のように条件分岐を書くが、これだと条件分岐の数が多くなってしまう。
<template>
<div v-if="currentScreen === 'home' ">
<star-button/>
</div>
<div v-else-if="currentScreen === 'search' ">
<setting-btn/>
</div>
</template>
だから、slotを使って、親コンポーネントに描画する内容を任せたい場面が出てくる。
書き方は?
子に渡したい値を子コンポーネント名で囲む。
#src/Parent.vue
<template>
<div class="home">
<DefaultLayout>酒ケジュールを提供します。</DefaultLayout>
#子コンポーネントに書かれている「最強のアルゴリズムを採用しています。」が優先される。
</div>
</template>
<script>
import DefaultLayout from '../components/DefaultLayout.vue'
export default {
components: {
DefaultLayout
}
}
</script>
slotを使わないと、コンポーネントに書かれている値が優先される。
この値をフォールバックコンテンツと言う。
#src/components/DefaultLayout
<template>
<div class="DefaultLayout">
<p>最強のアルコリズムを採用しています。</p>
</div>
</template>
<style>
</style>
#表示される内容
最強のアルコリズムを採用しています。
コンポーネント側のテンプレートに<slot>タグを記述すると、その場所ではスロットコンテンツが埋め込まれる。
#src/Parent.vue
<template>
<div class="home">
<DefaultLayout>酒ケジュールを提供します。</DefaultLayout>
#子でslotが使われているため、「酒ケジュールを提供します。」が優先される。
</div>
</template>
<script>
import DefaultLayout from '../components/DefaultLayout.vue'
export default {
components: {
DefaultLayout
}
}
</script>
親の状態に合わせて描画内容を変えたい場所をslotで囲む。
#src/components/DefaultLayout
<template>
<div class="DefaultLayout">
<p><slot>最強のアルコリズムを採用しています。</slot></p>
</div>
</template>
<style>
</style>
#表示される内容
酒ケジュールを提供します。
親側でスロットコンテンツ(DefaultLayoutで囲まれている部分)が定義されていた場合は、
<slot>タグで囲まれたコンポーネント側のコンテンツ(「最強のアルコリズムを採用しています。」)は表示されず、親側のスロットコンテンツが表示される。
名前付きスロット
複数のスロットがあると便利なときもある。
<default-layout>
コンポーネントが下記のようなテンプレートだった場合を考える。
#src/components/DefaultComponent.vue
<div class="container">
<h3>
<!-- ここに英語のコンテンツ -->
</h3>
<h3>
<!-- ここに日本語のコンテンツ -->
</h3>
</div>
複数のslotを追加することで、親コンポーネントで呼び出した時に、動的にコンテンツを描写することができる。
#src/components/DefaultComponent
<div class="container">
<h3>
<slot name="eng">I love you.</slot>
</h3>
<h3>
<slot name="jpn">ありがとう、私もよ。</slot>
</h3>
</div>
name
のない <slot>
要素は、暗黙的に「default」という名前を持つ。
<template>
に対して v-slot
ディレクティブを使って、スロット名を引数として与える。
そうすることで、slotにコンテンツを渡すことができる。
#src/Parent.vue
<DefaultLayout>
</DefaultLayout>
<DefaultLayout>
<template v-slot:eng>
<h3>I hate you.</h3>
</template>
</DefaultLayout>
<DefaultLayout>
<template v-slot:jpn>
<h3>悲しいわ。</h3>
</template>
</DefaultLayout>
<script>
import DefaultLayout from '../components/DefaultLayout.vue'
export default {
components: {
DefaultLayout
}
}
</script>
表示される内容
I love you.
ありがとう、私もよ。
I hate you.
ありがとう、私もよ。
I love you.
悲しいわ。
名前つきslotの省略記法
v-bind を 「:」、v-onを「@」で省略できるように、v-slotも「#」で省略して記述することができる。
#src/Parent.vue
<DefaultLayout>
</DefaultLayout>
<DefaultLayout>
<template #eng>
<h3>I hate you.</h3>
</template>
</DefaultLayout>
<DefaultLayout>
<template #jpn>
<h3>悲しいわ。</h3>
</template>
</DefaultLayout>
<script>
import DefaultLayout from '../components/DefaultLayout.vue'
export default {
components: {
DefaultLayout
}
}
</script>
スコープ付きslot
スコープを使うと、スロットコンテンツから、子コンポーネントの中だけで利用可能なデータにアクセスできる。
スコープ付きslotの記述方法
スコープ付きslotを利用するには、子コンポーネント側では、
<slot>
タグに対してv-bindをしようする必要がある。
親コンポーネント内でスロットコンテンツとして user を使えるようにするために、<slot> 要素の属性として user をバインドする:
#src/components/CurrentUser.vue
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
<script>
export default {
name: 'CurrentUser',
data () {
return {
user: {
lastName: 'nakano',
firstName: 'suabaru' // ←slot内で参照したいデータ
}
}
}
}
</script>
<slot> 要素にv-bindでバインドされた属性をスロットプロパティ と呼ぶ。
親スコープ内で v-slot の値として名前を指定することで、スロットプロパティを受け取ることができる。
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
slotProps は自分の好きな名前に変換することができる。
まとめ
- v-slotを使うことで、描画したい内容を親コンポーネントに任せることができる。
- 動的に値を変更したい箇所は<slot>で囲む
- v-slotは#,v-onは@,v-bindは:で省略することができる。
- 酒ケジュールとは、お酒の飲む順番の造語で、酒 + スケジュールを掛け合わせた言葉である。