KvcTable
テーブルコンポーネントです。行の追加/削除、ドラッグ&ドロップによる並び替えに対応しています。
ライブデモ
基本的な使い方
<template>
<kvc-table
v-model="tableData"
:columns="columns"
>
<template #name="{ row, index }">
<kvc-text-input v-model="row.name" />
</template>
<template #age="{ row, index }">
<kvc-text-input v-model="row.age" type="number" />
</template>
</kvc-table>
</template>
<script setup>
import { ref } from 'vue'
const columns = ref([
{ code: 'name', label: '名前', width: '200px' },
{ code: 'age', label: '年齢', width: '100px' }
])
const tableData = ref([
{ name: '田中太郎', age: 30 },
{ name: '佐藤花子', age: 25 }
])
</script>
プロパティ
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
| modelValue | Array<any> | [] | テーブルデータ(v-model) |
| columns | Array<KvcTableColumn> | [] | カラム定義 |
| minRows | number | 1 | 最小行数 |
| maxRows | number | - | 最大行数 |
| draggable | boolean | false | ドラッグ&ドロップによる並び替えを有効化 |
| animation | number | 150 | ドラッグ&ドロップのアニメーション時間(ミリ秒) |
| readOnly | boolean | false | 読み取り専用モード |
| hideOperations | boolean | false | 操作ボタンを非表示にするかどうか |
| recordUrl | string | - | レコードURLのベースURL |
| rowData | Array<KvcTableRowMeta> | - | 行データのメタ情報 |
KvcTableColumn 型
interface KvcTableColumn {
code: string // フィールドのコード
label: string // カラムのラベル
width?: string // カラムの幅(例: '200px', '30%')
}
イベント
| イベント名 | ペイロード | 説明 |
|---|---|---|
| update:modelValue | Array<any> | テーブルデータが変更されたときに発火 |
| add | (value: Array<any>, index: number) | 行が追加されたときに発火 |
| delete | (value: Array<any>) | 行が削除されたときに発火 |
スロット
テーブルの各セルは、カラムのcodeに対応するスロットでカスタマイズできます。
<template #[columnCode]="{ row, index }">
<!-- セルの内容 -->
</template>
スロットプロパティ:
row: 現在の行データindex: 行のインデックス
特徴
- 行の動的追加/削除
- 最小行数/最大行数の制御
- ドラッグ&ドロップによる行の並び替え(vue-draggable-next使用)
- スロットを使った柔軟なセル内容のカスタマイズ
- レコードURLリンク表示対応
使用例
基本的な使用
<template>
<kvc-table
v-model="products"
:columns="productColumns"
:min-rows="1"
:max-rows="10"
>
<template #name="{ row }">
<kvc-text-input v-model="row.name" placeholder="商品名" />
</template>
<template #price="{ row }">
<kvc-text-input v-model="row.price" type="number" placeholder="価格" />
</template>
<template #category="{ row }">
<kvc-dropdown v-model="row.category" :items="categories" />
</template>
</kvc-table>
</template>
<script setup>
import { ref } from 'vue'
const productColumns = ref([
{ code: 'name', label: '商品名', width: '300px' },
{ code: 'price', label: '価格', width: '150px' },
{ code: 'category', label: 'カテゴリ', width: '200px' }
])
const products = ref([
{ name: '商品A', price: 1000, category: 'electronics' },
{ name: '商品B', price: 2000, category: 'clothing' }
])
const categories = ref([
{ label: '電子機器', value: 'electronics' },
{ label: '衣類', value: 'clothing' },
{ label: '食品', value: 'food' }
])
</script>
様々な入力コンポーネントの使用
<template>
<kvc-table
v-model="tasks"
:columns="taskColumns"
>
<template #title="{ row }">
<kvc-text-input v-model="row.title" />
</template>
<template #priority="{ row }">
<kvc-dropdown v-model="row.priority" :items="priorities" />
</template>
<template #dueDate="{ row }">
<kvc-date-picker v-model="row.dueDate" />
</template>
<template #assignee="{ row }">
<kvc-autocomplete v-model="row.assignee" :items="users" />
</template>
<template #status="{ row }">
<kvc-radio v-model="row.status" :items="statuses" />
</template>
<template #tags="{ row }">
<kvc-checkbox v-model="row.tags" :items="tagOptions" />
</template>
</kvc-table>
</template>
<script setup>
import { ref } from 'vue'
const taskColumns = ref([
{ code: 'title', label: 'タイトル', width: '250px' },
{ code: 'priority', label: '優先度', width: '120px' },
{ code: 'dueDate', label: '期限', width: '150px' },
{ code: 'assignee', label: '担当者', width: '150px' },
{ code: 'status', label: 'ステータス', width: '200px' },
{ code: 'tags', label: 'タグ', width: '200px' }
])
const tasks = ref([
{
title: 'タスク1',
priority: 'high',
dueDate: '2024-12-31',
assignee: 'user1',
status: 'in-progress',
tags: ['urgent']
}
])
const priorities = ref([
{ label: '高', value: 'high' },
{ label: '中', value: 'medium' },
{ label: '低', value: 'low' }
])
const users = ref([
{ label: '田中太郎', value: 'user1' },
{ label: '佐藤花子', value: 'user2' },
{ label: '鈴木一郎', value: 'user3' }
])
const statuses = ref([
{ label: '未着手', value: 'not-started' },
{ label: '進行中', value: 'in-progress' },
{ label: '完了', value: 'completed' }
])
const tagOptions = ref([
{ label: '緊急', value: 'urgent' },
{ label: '重要', value: 'important' },
{ label: 'レビュー必要', value: 'needs-review' }
])
</script>
最小・最大行数の制御
<template>
<kvc-wrap>
<h3>参加者リスト(最低2人、最大10人)</h3>
<kvc-table
v-model="participants"
:columns="participantColumns"
:min-rows="2"
:max-rows="10"
>
<template #name="{ row }">
<kvc-text-input v-model="row.name" placeholder="名前" />
</template>
<template #email="{ row }">
<kvc-text-input v-model="row.email" type="email" placeholder="メールアドレス" />
</template>
<template #role="{ row }">
<kvc-dropdown v-model="row.role" :items="roles" />
</template>
</kvc-table>
</kvc-wrap>
</template>
<script setup>
import { ref } from 'vue'
const participantColumns = ref([
{ code: 'name', label: '名前', width: '200px' },
{ code: 'email', label: 'メールアドレス', width: '250px' },
{ code: 'role', label: '役割', width: '150px' }
])
const participants = ref([
{ name: '', email: '', role: 'member' },
{ name: '', email: '', role: 'member' }
])
const roles = ref([
{ label: 'メンバー', value: 'member' },
{ label: 'リーダー', value: 'leader' },
{ label: 'オブザーバー', value: 'observer' }
])
</script>
ドラッグ&ドロップ有効化
<template>
<kvc-table
v-model="fixedItems"
:columns="itemColumns"
draggable
>
<template #item="{ row }">
<kvc-text-input v-model="row.item" />
</template>
<template #value="{ row }">
<kvc-text-input v-model="row.value" type="number" />
</template>
</kvc-table>
</template>
<script setup>
import { ref } from 'vue'
const itemColumns = ref([
{ code: 'item', label: '項目', width: '300px' },
{ code: 'value', label: '値', width: '150px' }
])
const fixedItems = ref([
{ item: '項目1', value: 100 },
{ item: '項目2', value: 200 }
])
</script>
計算フィールドの実装
<template>
<kvc-wrap>
<kvc-table
v-model="orderItems"
:columns="orderColumns"
>
<template #product="{ row }">
<kvc-text-input v-model="row.product" />
</template>
<template #quantity="{ row }">
<kvc-text-input v-model.number="row.quantity" type="number" />
</template>
<template #price="{ row }">
<kvc-text-input v-model.number="row.price" type="number" />
</template>
<template #total="{ row }">
<span>¥{{ (row.quantity * row.price).toLocaleString() }}</span>
</template>
</kvc-table>
<div style="margin-top: 20px; text-align: right; font-size: 18px; font-weight: bold;">
合計: ¥{{ totalAmount.toLocaleString() }}
</div>
</kvc-wrap>
</template>
<script setup>
import { ref, computed } from 'vue'
const orderColumns = ref([
{ code: 'product', label: '商品名', width: '250px' },
{ code: 'quantity', label: '数量', width: '100px' },
{ code: 'price', label: '単価', width: '120px' },
{ code: 'total', label: '小計', width: '120px' }
])
const orderItems = ref([
{ product: '商品A', quantity: 2, price: 1000 },
{ product: '商品B', quantity: 1, price: 2500 }
])
const totalAmount = computed(() => {
return orderItems.value.reduce((sum, item) => {
return sum + (item.quantity * item.price)
}, 0)
})
</script>
TypeScript サポート
import type { KvcTableProps, KvcTableColumn } from '@zygapp/kintone-vue3-component'
interface TableRow {
name: string
age: number
}
const columns: KvcTableColumn[] = [
{ code: 'name', label: '名前', width: '200px' },
{ code: 'age', label: '年齢', width: '100px' }
]
const props: KvcTableProps = {
modelValue: [] as TableRow[],
columns: columns,
minRows: 1,
maxRows: 10,
draggable: true,
showRecordUrl: false
}
注意事項
- テーブルのデータは必ずリアクティブな配列(
refやreactive)を使用してください - 各行のデータは一意のキーを持つオブジェクトである必要があります
- ドラッグ&ドロップ機能を使用する場合、vue-draggable-nextライブラリがインストールされている必要があります
- 大量のデータを扱う場合は、パフォーマンスに注意してください