SwTable

SwTable 是管理台資料表格:columns 配置驅動表頭與列序,儲存格預設渲染 item[key],複雜內容(縮圖 / 狀態徽章 / 操作按鈕組)走 #cell-<key> 作用域插槽由業務自渲染;內建管理台高頻三大件——受控列排序(v-model:sort)、行選擇批量(v-model:selected)、loading 過渡,以及斑馬紋 / 密度 / 黏性表頭視覺旋鈕。視覺對齊 shadcn Table 基調。

語義 <table> 直出(SEO / a11y),根包一層 .sw-table 容器做 overflow-x: auto——窄螢幕時表格自身橫向滾動、不撐爆頁面。基線樣式(邊框 + 圓角 / 表頭弱化底 / 行 hover / 儲存格 padding)走 --sw-table-* token,applier 覆蓋變數即換膚。

邊界:分頁 / 篩選不內建——用 SwPagination / SwSegmented / SwSelect 頁面層組合;排序只管互動不排資料(受控,見下);固定列 / 列寬拖曳 / 樹形 / 虛擬滾動等重功能等真實資料點再議。這對齊 framework「只管佈局不綁業務 UI」鐵律。

基礎用法

基礎列(預設儲存格取 item[key])

加载中...
<script setup lang="ts">
const COLUMNS = [
  { key: 'name', label: '名称' },
  { key: 'category', label: '分类' },
  { key: 'count', label: '集数', width: '4rem', align: 'center' },
]
const rows = [{ id: 1, name: '未来都市', category: '动画', count: 12 }]
</script>

<template>
  <SwTable :columns="COLUMNS" :items="rows" />
</template>

儲存格 / 表頭插槽(營運台列表形態)

#cell-<key> 按列自訂儲存格(作用域 { item, value, index }),#header-<key> 自訂表頭(作用域 { column }):

狀態徽章 + 行內操作(#cell-* 插槽)

加载中...

空態佔位

#empty 在 items 為空時渲染為一行整寬佔位;不傳則空 tbody:

#empty 空態佔位

加载中...

列排序(受控)

column.sortable 讓列頭可點,三態循環 asc → desc → 無 並經 v-model:sort 受控回顯(表頭渲染指示箭頭 + aria-sort)。元件不排資料——業務拿到排序態後本地排(toSorted)或帶參調後端(管理台主流是伺服端排序):

列排序(受控三態,本 demo 本地排序)

加载中...
<script setup lang="ts">
const sort = ref<SwTableSort | undefined>()
// 伺服端排序:排序態變化即帶參重新拉資料
watch(sort, (s) => refetch({ orderBy: s?.key, order: s?.order }))
</script>

<template>
  <SwTable v-model:sort="sort" :columns="COLUMNS" :items="rows" />
</template>

行選擇與批量操作

selectable 渲染 checkbox 選擇列 + 表頭全選(部分選中時半選 indeterminate),選中集合走 v-model:selected(rowKey 值陣列):

行選擇 + 批量操作

加载中...

loading 過渡態

loading 讓表格半透明 + 遮罩轉圈,保留結構不閃白——服務「已有資料、翻頁 / 篩選刷新中」的過渡;首屏無資料的 loading 仍歸頁面層四態(骨架屏),兩者互補:

翻頁刷新過渡(loading + SwPagination 組合)

加载中...

視覺旋鈕:斑馬紋與密度

striped 偶數行弱化底、size="compact" 收緊儲存格 padding,資料密集頁常用組合:

斑馬紋 + 緊湊密度(可切換對比)

加载中...

黏性表頭(長列表容器內滾動)

sticky-header + --sw-table-max-height 讓容器變滾動區、表頭釘在頂部:

黏性表頭(30 行容器內滾動)

加载中...

管理台綜合形態

排序 + 行選批量 + loading + 行點擊 + 狀態徽章 + 行內操作的完整組合(真實營運台列表頁形態):

管理台綜合(全能力組合)

加载中...

與分頁組合(頁面層資料流)

表格不管分頁——頁碼翻頁用 SwPagination 受控替換 items:

<template>
  <SwTable :columns="COLUMNS" :items="pageItems">
    <template #empty>暂无数据</template>
  </SwTable>
  <SwPagination v-model:page="page" :total="total" :page-size="20" />
</template>

Props

名稱類型必填預設值說明
columnsSwTableColumn[]✓—列配置,每項 { key, label?, width?, align?, sortable? }
itemsT[]✓—行資料(泛型,元件不關心形狀)
rowKeystring | ((item: T) => string | number)'id'行 key 欄位名或取值函數;解析不出回退 index
stripedbooleanfalse斑馬紋(偶數行弱化底)
size'default' | 'compact''default'密度(compact 收緊儲存格 padding)。⚠️ 與 SwThemeSwitch / SwLangSwitch 的 size(圖示 px 數值)不是一回事——那兩個是尺寸、這個是密度列舉,對齊 Ant / Element 的 Table.size
stickyHeaderbooleanfalse黏性表頭(配 --sw-table-max-height 讓容器變滾動區)
loadingbooleanfalse刷新過渡態(遮罩 + 半透明,保留結構)
selectablebooleanfalse渲染 checkbox 選擇列 + 表頭全選
sort(v-model:sort)SwTableSort | undefinedundefined目前排序態;undefined = 無排序
selected(v-model:selected)(string | number)[][]選中行的 rowKey 值集合

SwTableColumn:{ key: string; label?: string; width?: string; align?: 'left' \| 'center' \| 'right'; sortable?: boolean }——key 既是預設儲存格取值欄位,也是 #cell-<key> / #header-<key> 插槽名後綴;width 落到 <th>(CSS 寬度值);align 預設 'left';sortable 讓列頭可點排序。

SwTableSort:{ key: string; order: 'asc' \| 'desc' }。兩個型別均可從套件名匯入:import type { SwTableColumn, SwTableSort } from '@swift-web/framework'。

Events

名稱攜帶說明
update:sortSwTableSort | undefined點 sortable 列頭觸發(asc → desc → undefined 三態循環)
update:selected(string | number)[]行選 / 全選變化
row-click(item, index)點擊行觸發(行內 button / a / input 等 interactive 元素的點擊不觸發);有監聽時行自動 cursor: pointer

行內操作(編輯 / 上下架 / 刪除)仍在 #cell-<key> 插槽內用 SwButton 等自帶事件。

Slots

名稱作用域參數說明
cell-<key>{ item, value, index }逐列自訂儲存格。不傳則渲染 String(item[key] ?? '')
header-<key>{ column }逐列自訂表頭。不傳則渲染 column.label。⚠️ 可排序列的插槽內容會被包進 <button>(鍵盤可達),故只能放 phrasing content——塞 <button> / <a> 會構成巢狀互動元素
empty—items 為空時渲染為一行整寬佔位(可選;不傳則空 tbody)

樣式定制 Token

表格皮膚經 --sw-table-* token 覆蓋(fallback 即預設視覺):

Token預設值作用點
--sw-table-bgvar(--card)表格底色
--sw-table-bordervar(--border)外框與行分隔線顏色
--sw-table-radiusvar(--radius)表格圓角
--sw-table-head-colorvar(--muted-foreground)表頭文字色
--sw-table-head-bgcolor-mix(in srgb, var(--foreground) 6%, transparent)表頭底色(foreground 疊加:任意主題下與行底可辨)
--sw-table-hover-bgcolor-mix(in srgb, var(--primary) 4%, transparent)行 hover 底色
--sw-table-striped-bgcolor-mix(in srgb, var(--foreground) 3%, transparent)斑馬紋偶數行底色(striped)
--sw-table-cell-padding0.75rem 1rem儲存格內邊距
--sw-table-cell-padding-compact0.375rem 0.75rem緊湊密度內邊距(size="compact")
--sw-table-font-sizeinherit表格字級
--sw-table-max-heightnone容器最大高(設值即容器內滾動,配 stickyHeader)

注意事項

  • 可排序表頭是真 <button>:sortable 列的表頭內容被包進 <button>(W3C ARIA APG 的 Sortable Table 範式),鍵盤可 Tab 聚焦、Enter / Space 排序,aria-sort 仍在 <th> 上。想改 hover 視覺請選 button.th-inner:hover。
  • row-click 是便捷層,不是唯一通路:行本身刻意不做成可聚焦元素(長表會憑空多出等量 Tab 停靠點)。行內必須有承擔同一動作的真實可聚焦元素(詳情連結 / 操作按鈕),否則鍵盤與螢幕閱讀器使用者根本觸達不了該動作——那是 WCAG 2.1.1 Keyboard(Level A)不達標,且滑鼠測試永遠看不出來。dev 期會 console.warn 提示,生產建置整段被移除。
  • 排序不排資料:v-model:sort 只是受控互動態——業務必須自己排(本地 toSorted 或帶參調後端),否則點了列頭「只有箭頭變、資料不動」。
  • loading 與四態的分工:loading 服務「已有資料刷新中」的過渡;首屏無資料的 loading / error / empty 仍歸頁面層四態(骨架屏 / 重試入口),#empty 僅是空資料行的輕量兜底。
  • 行內操作不觸發 row-click:#cell-* 內的 button / a / input 點擊不會冒泡成行點擊,無需手動 stopPropagation。
  • 不內建分頁 / 篩選:用 SwPagination / SwSegmented / SwSelect 頁面層組合。
  • 行內非同步操作記得鎖 pending:#cell-* 裡的操作按鈕遵守 SB-001(async @click 配 :loading),如上下架按行 id 鎖。
  • 窄螢幕橫向滾動是內建行為:.sw-table 容器自帶 overflow-x: auto,列多時給列設 width 保證可讀寬度即可,別在外層再包滾動容器。

相關