- 我的帖子已经打上 开源推广 标签: 是
- 我的开源项目完整开源,无未开源部分: 是
- 我的开源项目已链接认可 LINUX DO 社区: 是
- 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是
- 以上选择我承诺是永久有效的,接受社区和佬友监督: 是
以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出
项目地址:GitHub - parade0393/vtable-guild · GitHub
首先说明:这是一个 vibe coding 的项目。大部分代码由 AI 协作产出,把关、调试、痛点收集都是我自己做的。下面要聊的所有技术细节都能在仓库里翻到对应源码。
一、这是一个什么组件
- 基于 Vue 3 Composition API + TSX,全部子组件用 TSX 写
- 基于 Tailwind CSS 4 +
@tailwindcss/vite - 三层主题模型:默认预设 → 全局配置 → 实例 props,颗粒度细到单个 slot
- 当前内置两套预设:
antdv(默认)和element-plus,运行时可切换 - 该有的能力都有:虚拟滚动、固定列、固定表头、树形、行展开、行选择、排序筛选、列拖拽 resize、表头分组、自定义渲染、国际化
二、为什么会有这个项目
经常做中后台管理系统,table 是高频组件。
ant-design-vue
- 不支持虚拟滚动。几千行数据就开始明显卡。
- 滚动条恶心。固定表头 + bordered 的时候,表头会多出一列对齐滚动条的空白列,强迫症看着难受。
- 斑马纹没有开箱支持。要自己写 CSS。
- 改样式不方便。要么覆盖 className 跟权重打架,要么用 ConfigProvider 但粒度太粗,要么改 less 变量改一片连带影响。
element-plus
- 不支持虚拟滚动。
el-table没有,el-table-v2支持但 API 是另一套——换组件名 + 重新写 column 定义,老项目想加虚拟滚动等于换轮子。 - 不支持列配置驱动。所有列必须用
<el-table-column>写在模板里,动态列要么 v-for 一堆,要么 JSX 绕路。 - UI 不如 ant-design-vue。这个见仁见智,但我们团队的偏好是 antdv。
vxe-table
- 太重。功能确实多,但要引入它的整套生态,单独一个 table 的成本太大。
- 样式不兼容。和现有系统的 UI 风格不一致,定制起来同样费劲。
tanstack-table
- headless。本身是个无 UI 的「状态机」,要做大量封装才能用起来。如果项目里其它组件都是有 UI 的,单独引入一个 headless 又得自己实现一整套表头/单元格/筛选/排序的 UI。
所以做了 vtable-guild,目标是补齐这些缺失,但不重新发明轮子——API 保留 antdv 风味,老项目最小改动接入;样式系统重新做,让定制变得简单。
三、vtable-guild 的特色
3.1 能用它做什么 —— 一张能力矩阵
下面这些能力当前都已实现,可以在 playground(pnpm playground)找到对应的对照演示页。
sortOrder) + uncontrolled (defaultSortOrder)
✓
筛选(菜单 / 树形 / 搜索 / 完全自定义 dropdown)
filterMode、filterSearch、filterDropdown
✓
行选择
rowSelection (checkbox / radio),支持树形联动
✓
树形数据
expandedRowKeys / defaultExpandedRowKeys / childrenColumnName
✓
行展开(非树形)
expandable.expandedRowRender
✓
固定列 / 固定表头
column.fixed + scroll.y + sticky
✓
表头分组
column.children
✓
自定义渲染
customRender / customCell / customHeaderCell
✓
局部化
内置 zh-CN / en-US + localeOverrides
✓
列拖拽 resize
column.resizable + minWidth / maxWidth 约束
✓
虚拟滚动
virtual + scroll.y 显式启用
独有
主题预设切换
themePreset: 'antdv' | 'element-plus'
独有
3.2 迁移成本:从 antdv Table 切过来,column 配置一行不改
这个组件最大的「不挑食」体现在 API 上——column 配置、change 事件、rowSelection、expandable、scroll、sticky、size 这些 prop 的命名和语义全部对齐 ant-design-vue。
实际迁移的工作量大概是这样:
- import { Table } from 'ant-design-vue'
+ import { VTable } from '@vtable-guild/vtable-guild'
- <a-table :columns="columns" :data-source="data" @change="onChange" />
+ <VTable :columns="columns" :data-source="data" @change="onChange" />
columns 数组里的对象、onChange 里的参数解构,理论上都不需要动。
唯一需要注意的差异:虚拟滚动需要显式开启 virtual=true + scroll.y,不是大数据量自动启用。
3.3 主题随便改:三层覆盖 + CSS 变量驱动 + 预设切换
这是 vtable-guild 最想解决的痛点,也是花心思最多的地方。
三层主题,从粗到细层 1:选预设——99% 场景这一层就够了。
// main.ts
import { createApp } from 'vue'
import { createVTableGuild } from '@vtable-guild/vtable-guild'
import '@vtable-guild/vtable-guild/css'
const app = createApp(App)
app.use(createVTableGuild({ themePreset: 'antdv' })) // 或 'element-plus'
层 2:全局批量覆盖某个 slot——想统一改所有表格的表头样式?这一层。
app.use(createVTableGuild({
themePreset: 'antdv',
theme: {
table: {
slots: {
th: 'bg-slate-900 text-white',
td: 'text-slate-700',
},
defaultVariants: { size: 'middle' },
},
},
}))
这里出现了一个关键概念:slots。tailwind-variants 的核心是把一个组件拆成多个命名 slot——比如表格的 root / table / thead / tbody / tr / th / td,再加上排序、筛选、空态等等。每个 slot 各自一份 class 字符串。
层 3:单实例覆盖——只想改这一个表格的某个 slot。
<template>
<VTable
:columns="columns"
:data-source="data"
:ui="{ th: 'bg-blue-50', tr: 'hover:bg-blue-50/40' }"
class="rounded-2xl shadow-sm"
/>
</template>
ui prop 按 slot 名覆盖,class 自动落到 root slot。
CSS 文件里有三层:语义 token → 组件 token → slots class 引用组件 token。
/* packages/theme/css/presets/antdv.css */
:where(:root),
[data-vtg-preset='antdv'] {
/* 语义 token */
--color-surface: #ffffff;
--color-on-surface: rgb(0 0 0 / 88%);
--color-default: #f0f0f0;
--color-primary: #1677ff;
/* 组件 token,100% 引用语义 token */
--vtg-table-bg: var(--color-surface);
--vtg-table-header-bg: var(--color-surface-hover);
--vtg-table-border-color: var(--color-default);
}
.dark [data-vtg-preset='antdv'],
[data-vtg-preset='antdv'].dark {
/* 暗色只覆盖语义 token,组件 token 自动跟随 */
--color-surface: #141414;
--color-on-surface: rgb(255 255 255 / 85%);
}
切暗色模式只要给 <html> 加 .dark,所有 slots 自动响应。要切 element-plus 预设,把 data-vtg-preset 改成 element-plus 即可。
一句话总结这一节:想从 antdv 风切到 element-plus 风?改一个字符串。想统一全局改?传 theme 配置。想改单个表格?用 ui prop。想做完全自己的视觉?写一个 preset 对象。
3.4 大数据不卡:虚拟滚动 + 树形
虚拟滚动的接入开启方式就一行:
<VTable virtual :scroll="{ y: 400 }" :columns="columns" :data-source="bigData" />
columns 定义、排序筛选、固定列、行选择,全都和不开虚拟滚动时一样——这是和 element-plus v2 路线最大的区别:不是另一个组件、另一套 API,而是同一个 <VTable> 加一个 virtual prop。
组件的效果图如下


1 个帖子 - 1 位参与者