スロット
スロット は、親コンポーネントから子コンポーネントの特定の場所にテンプレートを差し込むための仕組みです。 コンポーネントを「箱」として使い、その中に好きなHTMLや部品を入れることができます。
<!-- AppButton: 子コンポーネント -->
<template>
<button type="button" class="app-button">
<slot /> <!-- スロットアウトレット -->
</button>
</template>
<style scoped>
.app-button {
padding: 0.375rem 1rem;
border-radius: 0.375rem;
border: none;
font-size: 0.875rem;
background-color: #02c169;
color: #fff;
}
</style>
<!-- 親コンポーネント -->
<template>
<AppButton>
<!-- ↓ スロットコンテンツ -->
<span>✅</span>
<span class="padding-start-1">すべて完了にする</span>
<!-- ↑ スロットコンテンツ -->
</AppButton>
</template>
<slot> 要素は、親が提供した スロットコンテンツ をレンダリングすべき場所を示す スロットアウトレット です。
フォールバックコンテンツ(デフォルト)
親からスロットコンテンツが渡されなかった場合に、フォールバック(つまりデフォルト)を設定することもできます。
やり方は <slot> 要素の間に、フォールバックコンテンツを設定します。
<!-- AppButton: 子コンポーネント -->
<template>
<button type="button" class="app-button">
<slot>
ボタン <!-- フォールバックコンテンツ -->
</slot>
</button>
</template>
<style scoped>
/* 省略 */
</style>
<!-- 親コンポーネント -->
<template>
<AppButton />
</template>
この例では、親コンポーネントから、 slot を渡していませんが、
フォールバックコンテンツを設定しているので、「ボタン」と表示されます。
名前付きスロット
<slot> に名前を付けると、1つのコンポーネントに複数の差し込み場所(スロットアウトレット)が作れます。
名前付きのスロットコンテンツを渡すためには、 v-slot を利用します。(例: <template v-slot:title>)
v-slot は # で省略表記ができます。(例: <template #title>)
<!-- AppModal: 子コンポーネント -->
<template>
<div
role="dialog"
aria-labelledby="dialogTitle"
aria-describedby="dialogDesc"
class="modal"
>
<h2 id="dialogTitle">
<slot name="title" /> <!-- titleという名前の スロットアウトレット -->
</h2>
<div id="dialogDesc">
<slot />
</div>
</div>
</template>
<!-- 親コンポーネント -->
<template>
<AppModal>
<template #title>
<!-- v-slot. 上のように # で省略表記ができます -->
<!-- ↓ titleという名前の スロットコンテンツ -->
<span>✏️</span>
<span class="padding-start-1">タスクの編集</span>
<!-- ↑ titleという名前の スロットコンテンツ -->
</template>
<form>
<div>
<label for="title">タイトル</label>
<input id="title" v-model="inputTitle" type="text" required>
</div>
</form>
</AppModal>
</template>
名前なし(name を持たない)スロットは、暗黙的に default という name を持つものとされますので、
以下のようにも記述できます。
<!-- 親コンポーネント -->
<template>
<AppModal>
<template #title>
<span>✏️</span>
<span class="padding-start-1">タスクの編集</span>
</template>
<template #default>
<form>
<div>
<label for="title">タイトル</label>
<input id="title" v-model="inputTitle" type="text" required>
</div>
</form>
</template>
</AppModal>
</template>
ポイント
<slot name="xxx" />に対して<template #xxx>で中身を渡す- 名前なしスロット(デフォルト)と混ぜて使える
まとめ
- スロットは、コンポーネントの中の特定位置にテンプレートを差し込む機能
slotは、フォールバック(デフォルト)を設定することもできる- 名前付きスロットを使えば、差し込み場所を増やせる
現在の実装の課題
- タスクを新規作成するためのフォームが表示されていません。
AppModalコンポーネントのタイトルが「新規作成モーダル」という、固定の名前になっていて、汎用性がない状態になっています。
チャレンジ
1. AppModal.vue に <slot> を追加
AppModal.vue に、
- モーダルのタイトル
- モーダルのコンテンツ
が差し込みできるよう、 <slot> を追加してみましょう。
AppModal.vueの<h2>新規作成モーダル</h2>を削除して<slot name="title" />を追加しましょう。AppModal.vueに、モーダルコンテンツを追加するための<slot />を追加しましょう。
2. AppModal コンポーネントに、モーダルタイトルと新規作成フォームの v-slot を追加
app.vueでAppModalコンポーネントに、モーダルタイトルのv-slot<template #title><h2>タスクの新規作成</h2></template>を追加しましょう。app.vueでAppModalコンポーネントに、v-slot(名前なし)に、以下のHTMLを追加しましょう。
<form>
<div>
<label for="title">タイトル</label>
<input id="title" type="text" required />
</div>
<div>
<label for="note">メモ</label>
<textarea id="note" rows="2" />
</div>
<div>
<label for="dueDate">期限</label>
<input id="dueDate" type="date" />
</div>
<div>
<button type="submit">登録</button>
</div>
</form>
もし行き詰まったら、以下のボタンをクリックして解答を見ることができます。