Vueのスロット(slot)を理解してVuetifyの関数付きスロット活用へつなげる実践例:v-data-table
で行操作を柔軟にカスタマイズ
Vueには「スロット(slot)」という仕組みがあり、親コンポーネントが子コンポーネントにテンプレートを差し込むことで、柔軟なコンポーネント設計ができます。
この記事では、まず Vueのスロットの基本構文と考え方を解説し、その後、VuetifyのUIコンポーネントでスロットを活用する実践例として、v-data-table
で関数をスロット経由で使って行操作する方法を紹介します。
スロットとは?
スロットは、Vueで親コンポーネントが子コンポーネントにテンプレート(HTML)やロジック(変数・関数)を渡すための仕組みです。
例:デフォルトスロット
<!-- 子コンポーネント -->
<template>
<div class="card">
<slot></slot> <!-- 親からのコンテンツをここに挿入 -->
</div>
</template>
<!-- 親コンポーネント -->
<MyCard>
<p>これはカードの中身です。</p>
</MyCard>
スコープ付きスロット
スロットに値や関数を渡したい場合、スコープ付きスロットを使います。
<!-- 子コンポーネント -->
<template>
<slot :count="count" :increment="increment"></slot>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => { count.value++ }
</script>
<!-- 親コンポーネント -->
<MyCounter v-slot="{ count, increment }">
<p>現在のカウント: {{ count }}</p>
<button @click="increment">カウントアップ</button>
</MyCounter>
Vuetifyのスロット活用へ
Vuetifyの多くのコンポーネントでも、スロットから関数や状態を受け取れる「スコープ付きスロット」が提供されています。
代表的な例が v-data-table
の item
スロットです。
実践:v-data-table
でスロットから関数を受け取り、行を操作する
目標
- スロットから Vuetify が提供する関数(
isSelected
,toggleSelect
)を受け取って行の選択状態を制御する - 各行に「削除」ボタンを追加して独自の操作を実装する
実装例
<template>
<v-data-table
:items="desserts"
item-value="name"
show-select
v-model:selected="selected"
>
<!-- itemスロット:各行のカスタム描画 -->
<template #item="{ item, isSelected, toggleSelect }">
<tr :style="{ backgroundColor: isSelected(item) ? '#f0f0f0' : '' }">
<td>
<v-btn icon @click="toggleSelect(item)">
<v-icon>
{{ isSelected(item) ? 'mdi-checkbox-marked' : 'mdi-checkbox-blank-outline' }}
</v-icon>
</v-btn>
</td>
<td>{{ item.name }}</td>
<td>{{ item.calories }}</td>
<td>
<v-btn color="error" @click="removeItem(item)">削除</v-btn>
</td>
</tr>
</template>
</v-data-table>
</template>
<script setup>
import { ref } from 'vue'
const selected = ref([])
const desserts = ref([
{ name: 'プリン', calories: 300 },
{ name: 'アイスクリーム', calories: 200 },
{ name: 'ケーキ', calories: 400 },
])
const removeItem = (item) => {
desserts.value = desserts.value.filter(d => d.name !== item.name)
}
</script>
#は何の略?(v-slotの省略記法)
Vueでは、スロットを使うときに v-slot:
というディレクティブを指定できます。たとえば:
<template v-slot:item>
カスタム行
</template>
この v-slot:
は、Vue 2.6 以降で導入された構文で、以下のように #
に省略して書くことができます:
<template #item>
カスタム行
</template>
Vuetifyのドキュメントではスロット名が item.data-table-expand
のように書かれていますが、Vueテンプレート内では #item.data-table-expand
のように使用します。
Vuetifyのドキュメントからの読み解き方
Vuetifyの公式ドキュメントに記載されているスロット名(例:item.${string}
や header.${string}
)は、そのままVueテンプレートの#item.カラム名
のように変換して使えます。
例:
-
item.${string}
→<template #item.name>
や<template #item.calories>
のように使用(カラム名に対応) -
item.data-table-expand
→<template #item.data-table-expand>
-
header.${string}
→<template #header.name>
つまり、item.${string}
や header.${string}
のような表記は、カラム名ごとのセル/ヘッダーのカスタマイズが可能という意味です。
このように、Vuetifyのドキュメントを見ながら、スロット名に #
をつけ、${string}
の部分を実際のカラムキーに置き換えるだけで、目的のカスタマイズができるようになります。
まとめ
- Vueのスロットは、テンプレートの差し込みだけでなく値や関数も親に渡せる強力な仕組み
- Vuetifyでは、多くのコンポーネントがスコープ付きスロットを通じて関数や状態を提供している
- ドキュメントのスロット名(例:
item.${string}
)に#
をつけて${string}
を実際のカラムキーに置き換えれば Vueテンプレートで使用可能 -
v-data-table
のitem
,item.${string}
,header.${string}
などは、行やセル単位での柔軟な描画カスタマイズが可能