在上一篇中介紹了 開源免費可自訂的元件庫 shadcn-vue ,今天就來練習使用它裡面的 Data Table。不過他並不是從頭寫元件,而是使用 TanStack 的 Table 的 Vue 的版本,也是一個可以完全控制樣式的開源套件。
因為是使用到 @tanstack/vue-table ,所以還是必須要安裝套件:
安裝好後會發現 components\ui\table 資料夾內多了很多檔案。
在 components 資料夾中建立 UserTable.vue 檔案,先在 script 區塊中定義表格資料物件和欄位定義
加入 Data Table 和資料的定義,使用 onMounted 的寫法方便未來替換為從 API 中取得資料:
在其他頁面要使用這個表格很簡單:
也可以自訂條件,例如 email 欄位長度超過 15 個字元就使用紅色粗體顯示:
參考資料:
npm - @tanstack/vue-table
TanStack - Vue Table
shadcn-vue - Data Table
安裝套件
依照上一篇安裝好 shadcn-vue 後要安裝 Data Table 就很簡單:
npx shadcn-vue@latest add table
因為是使用到 @tanstack/vue-table ,所以還是必須要安裝套件:
npm install @tanstack/vue-table
安裝好後會發現 components\ui\table 資料夾內多了很多檔案。
基本表格
為了方便複用,我們先把最基本的樣板程式碼和其他 DataTable 元件一樣放到 components\ui\table 資料夾中,檔名就叫做 DataTable.vue
<script setup lang="ts" generic="TData, TValue">
import type { ColumnDef } from '@tanstack/vue-table'
import {
FlexRender,
getCoreRowModel,
useVueTable,
} from '@tanstack/vue-table'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
const props = defineProps<{
columns: ColumnDef<TData, TValue>[]
data: TData[]
}>()
const table = useVueTable({
get data() { return props.data },
get columns() { return props.columns },
getCoreRowModel: getCoreRowModel(),
})
</script>
<template>
<div class="border rounded-md">
<Table>
<TableHeader>
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
<TableHead v-for="header in headerGroup.headers" :key="header.id">
<FlexRender
v-if="!header.isPlaceholder" :render="header.column.columnDef.header"
:props="header.getContext()"
/>
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<template v-if="table.getRowModel().rows?.length">
<TableRow
v-for="row in table.getRowModel().rows" :key="row.id"
:data-state="row.getIsSelected() ? 'selected' : undefined"
>
<TableCell v-for="cell in row.getVisibleCells()" :key="cell.id">
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
</TableCell>
</TableRow>
</template>
<template v-else>
<TableRow>
<TableCell :colspan="columns.length" class="h-24 text-center">
No results.
</TableCell>
</TableRow>
</template>
</TableBody>
</Table>
</div>
</template>
在 components 資料夾中建立 UserTable.vue 檔案,先在 script 區塊中定義表格資料物件和欄位定義
import type {ColumnDef} from "@tanstack/vue-table";
/**
* 定義使用者資料
*/
interface User {
id: string
userName: string
displayName: string
email: string
}
/**
* 使用者資料表的欄位定義
*/
const columns: ColumnDef<User>[] = [
{
accessorKey: 'id',
header: 'ID',
},
{
accessorKey: 'userName',
header: '帳號',
},
{
accessorKey: 'displayName',
header: '名稱',
},
{
accessorKey: 'email',
header: 'Email',
},
]
加入 Data Table 和資料的定義,使用 onMounted 的寫法方便未來替換為從 API 中取得資料:
<template>
<DataTable :columns="columns" :data="data"/>
</template>
<script setup lang="ts">
import {onMounted, ref} from 'vue'
import type {ColumnDef} from "@tanstack/vue-table";
import DataTable from '@/components/ui/table/DataTable.vue'
/**
* 定義使用者資料
*/
interface User {
id: string
userName: string
displayName: string
email: string
}
/**
* 使用者資料表的欄位定義
*/
const columns: ColumnDef<User>[] = [
{
accessorKey: 'id',
header: 'ID',
},
{
accessorKey: 'userName',
header: '帳號',
},
{
accessorKey: 'displayName',
header: '名稱',
},
{
accessorKey: 'email',
header: 'Email',
},
]
const data = ref<User[]>([])
async function getData(): Promise<User[]> {
// 可以替換為從 API 取得資料
return [
{
id: 'a001',
userName: 'ruyut',
displayName: 'Ruyut',
email: 'a@ruyut.com'
},
{
id: 'a002',
userName: 'qwer123',
displayName: '小明',
email: 'qwer123@ruyut.com'
},
]
}
onMounted(async () => {
data.value = await getData()
})
</script>
在其他頁面要使用這個表格很簡單:
<template>
<UserTable></UserTable>
</template>
<script setup lang="ts">
import UserTable from '@/components/user-table/UserTable.vue'
</script>
自訂欄位樣式
在前面的 UserTable.vue 檔案中有建立資料表欄位定義,我們可以透過修改定義將 id 欄位變成粗體:
import type {ColumnDef} from "@tanstack/vue-table";
/**
* 使用者資料表的欄位定義
*/
const columns: ColumnDef<User>[] = [
{
accessorKey: 'id',
header: 'ID',
cell: ({ row }) => {
return h('strong', row.getValue('id'))
},
},
]
也可以自訂條件,例如 email 欄位長度超過 15 個字元就使用紅色粗體顯示:
import type {ColumnDef} from "@tanstack/vue-table";
/**
* 使用者資料表的欄位定義
*/
const columns: ColumnDef<User>[] = [
{
accessorKey: 'id',
header: 'ID',
cell: ({ row }) => {
return h('strong', row.getValue('id'))
},
},
{
accessorKey: 'email',
header: 'Email',
cell: ({row}) => {
const email: string = row.getValue('email')
// 如果長度超過 15 個字元,就用紅色粗體
if (email.length > 15) {
return h('strong', {class: 'text-red-500'}, email)
}
return email
},
},
]
參考資料:
npm - @tanstack/vue-table
TanStack - Vue Table
shadcn-vue - Data Table
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com