【Nuxt 2】スロット(slot)
Nuxt2
2021/05/25
スロットコンテンツ
以下のようにmy-button
コンポーネントを作成します。
MyButton.vue
<template>
<button>
<slot></slot>
</button>
</template>
<slot>
には、以下のようにmy-button
内に記述したコンテンツが展開されます。
<my-button>Click Me!</my-button>
展開結果
<button>Click Me!</button>
当然テキストだけでなく、要素や他のコンポーネントも展開されます。
<my-button><span class="bold">Click Me!</span></my-button>
展開結果
<button><span class="bold">Click Me!</span></button>
<slot>
内のコンテンツは、デフォルト値となります。
MyButton.vue
<template>
<button>
<slot>My Button!</slot>
</button>
</template>
<my-button></my-button> <my-button>Click Me!</my-button>
展開結果
<button>My Button!</button>
<button>Click Me!</button>
名前付きスロット
以下のように<slot>
にname
属性を設定することで、複数のスロットを使用することができます。
MyCard.vue
<div class="card">
<div class="card__header">
<slot name="header"></slot>
</div>
<div class="card__contents">
<slot></slot>
</div>
<div class="card__footer">
<slot name="footer"></slot>
</div>
</div>
コンポーネントを使用する際は、<template>
とv-slot
を使って名前を指定します。
<my-card>
<template v-slot:header>
<p>My Card Title</p>
</template>
<template v-slot:default>
<ul>
<li>contents1</li>
<li>contents2</li>
<li>contents3</li>
</ul>
</template>
<template v-slot:footer>
<p>My Card Footer</p>
</template>
</my-card>
展開結果
<div class="card">
<div class="card__header">
<p>My Card Title</p>
</div>
<div class="card__contents">
<ul>
<li>contents1</li>
<li>contents2</li>
<li>contents3</li>
</ul>
</div>
<div class="card__footer">
<p>My Card Footer</p>
</div>
</div>
<template v-slot:default>
は省略することができます。
またv-slot
は#
で省略することができます。
<my-card>
<template #header>
<p>My Card Title</p>
</template>
<template #default>
<ul>
<li>contents1</li>
<li>contents2</li>
<li>contents3</li>
</ul>
</template>
<template #footer>
<p>My Card Footer</p>
</template>
</my-card>
スロットプロパティ
スロットプロパティとは、親が<slot>
を通じてコンポーネントのデータやプロパティにアクセスするためのものです。
以下の例をみてください。
UserView.vue
<template>
<div>
<p>
<slot #id :user="user">{{ user.id }}</slot>
<slot #name :user="user">{{ user.name }}</slot>
</p>
</div>
</template>
<script>
export default {
data: () => ({
user: {
id: 1,
name: 'Taro'
}
})
}
</script>
表示結果
1
Taro
注目する点は、<slot>
でバインドしている:user="user"
の部分です。
このようにバインドした属性は、スロットプロパティとして設定されます。
スロットプロパティは、v-slot
(あるいは#
)で以下のように親から参照することができます。
参照した値はスロット内でのみ使用可能です。
<user-view>
<template #name="{ user }">{{ user.name.toUpperCase() }}</template>
</user-view>
表示結果
1
TARO
サンプル(table)
ID | 名前 | 年齢 | 性別 |
---|---|---|---|
1 | TANAKA | 20歳 | 男 |
2 | SUZUKI | 26歳 | 女 |
3 | YAMADA | 30歳 | 女 |
4 | ITO | 18歳 | 不明 |
5 | KATO | 40歳 | 男 |
MyTable.vue
<template>
<table>
<thead>
<tr>
<th v-for="header in headers" :key="header.value">
{{ header.text }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, i) in items" :key="i">
<td v-for="header in headers" :key="header.value">
<slot :name="header.value" :item="item">
{{ item[header.value] }}
</slot>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
headers: {
type: Array,
required: true,
},
items: {
type: Array,
required: true,
},
},
}
</script>
Page
<template>
<my-table :headers="headers" :item="items">
<template #id="{ item }">
<span style="color: red">{{ item.id }}</span>
</template>
<template #name="{ item }">
{{ item.name.toUpperCase() }}
</template>
<template #age="{ item }">
{{ item.age }}歳
</template>
</my-table>
</template>
<script>
export default {
data: () => ({
headers: [
{ text: 'ID', value: 'id' },
{ text: '名前', value: 'name' },
{ text: '年齢', value: 'age' },
{ text: '性別', value: 'gender' },
],
items: [
{ id: 1, name: 'Tanaka', age: 20, gender: '男' },
{ id: 2, name: 'Suzuki', age: 26, gender: '女' },
{ id: 3, name: 'Yamada', age: 30, gender: '女' },
{ id: 4, name: 'Ito', age: 18, gender: '不明' },
{ id: 5, name: 'Kato', age: 40, gender: '男' },
],
}),
}
</script>