Vuetify v-table 完全指南:轻量表格组件的 Props、Slots 与 Sass 定制
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
v-table是 Vuetify 组件库中最基础的表格组件,它是对原生 HTML<table>元素的一层轻量封装,在保留<thead>、<tbody>、<tr>、<td>等原生标签语义的同时,注入 Material Design 风格的外观与交互。本文基于 Vuetify 官方文档(tables.md)并结合源码实现,系统讲解v-table的全部 Props、Slots、样式变量与底层渲染机制,读完你可以直接用它构建从静态数据展示到固定表头、斑马纹、悬停高亮等各类轻量表格场景。
v-table 是什么:轻量包装,而非重型数据表格
在 Vuetify 的表格家族中,v-table属于"简单"的一端。官方文档对它的定位是:
The simpler of the table components is
v-table, a basic wrapper component for the HTML<table>element. In addition, regular table elements such as<thead>,<tbody>,<tr>, and<td>work by default.
即:它是对原生<table>元素的基础包装组件,原生表格标签(<thead>、<tbody>、<tr>、<td>等)默认即可直接使用,不需要额外注册或转换。这意味着你现有的手写 HTML 表格结构可以近乎零成本迁移到 Vuetify 的视觉体系下。
从源码看,组件定义位于 VTable.tsx,通过genericComponent创建,inheritAttrs: false,最终渲染为一个v-table类名的根元素,内部结构为:
<props.tag class="v-table ..."> <!-- 默认 tag 为 div --> └─ <div class="v-table__wrapper"> <!-- 可滚动容器 --> └─ <table> <!-- 原生 table -->值得注意的是,v-table并不像v-data-table那样内置排序、分页、筛选等数据能力。若需要这些高级功能,官方文档明确指向更复杂的表格组件v-data-table(其示例可见 packages/docs/src/examples/v-data-table)。选择原则很简单:纯展示用v-table,需要数据操作能力时升级到v-data-table。
基本用法:从原生表格到 v-table
v-table的使用方式与原生表格几乎一致,把<table>换成<v-table>即可。官方 Usage 示例(usage.vue)如下:
<template> <v-table> <thead> <tr> <th class="text-left">Name</th> <th class="text-left">Calories</th> </tr> </thead> <tbody> <tr v-for="item in desserts" :key="item.name"> <td>{{ item.name }}</td> <td>{{ item.calories }}</td> </tr> </tbody> </v-table> </template> <script> export default { data () { return { desserts: [ { name: 'Frozen Yogurt', calories: 159 }, { name: 'Ice cream sandwich', calories: 237 }, { name: 'Eclair', calories: 262 }, { name: 'Cupcake', calories: 305 }, { name: 'Gingerbread', calories: 356 }, { name: 'Jelly bean', calories: 375 }, { name: 'Lollipop', calories: 392 }, { name: 'Honeycomb', calories: 408 }, { name: 'Donut', calories: 452 }, { name: 'KitKat', calories: 518 }, ], } }, } </script>要点说明:
- 数据仍由你自己管理(这里用
v-for渲染行),v-table只负责外观与布局。 - 官方示例中在
<th>上使用了text-left工具类对齐表头文字,这是 Vuetify 内置的文本对齐 utility。 - 源码中表头单元格默认
text-align: start(见 VTable.sass),即默认靠左对齐,符合 Material Design 数据表格规范。
Props 全解析:从主题到斑马纹
v-table的 Props 定义在 VTable.tsx 的makeVTableProps中,共 6 个专属 Props,外加从 composables 混入的tag、theme、density、class、style等通用 Props。下面逐一展开。
theme:切换表格主题
通过themeprop 可以将表格切换到另一套主题(如暗色),无需改变全局主题配置。示例(prop-dark.vue):
<v-table theme="dark"> <!-- thead / tbody 内容同上 --> </v-table>底层实现:theme来自makeThemeProps,在 setup 中通过provideTheme(props)提供主题上下文(VTable.tsx),生成的themeClasses会追加到根元素的 class 列表上。表格背景与文字颜色由 Sass 变量$table-background(rgb(var(--v-theme-surface)))与$table-color(theme-color('on-surface', var(--v-high-emphasis-opacity)))控制(见 _variables.scss),因此切换主题时颜色会随 CSS 变量自动联动。
density:表格密度
densityprop 控制行高与表头高度,取值与全局密度体系一致:default、comfortable、compact。示例(prop-dense.vue):
<v-table density="compact"> <!-- 更紧凑的行间距 --> </v-table>底层实现:密度通过useDensity(props)composable 计算densityClasses,在 VTable.sass 中通过tools.density('v-table', $table-density)生成带修饰符的 CSS 变量:
@include tools.density('v-table', $table-density) using ($modifier) --v-table-header-height: #{$table-header-height + $modifier} --v-table-row-height: #{$table-row-height + $modifier}配合 _variables.scss 中$table-density: ('default': 0, 'comfortable': -2, 'compact': -4),可以算出三种密度下精确的行高:
| density | 表头高度(默认 56px + 修正值) | 行高(默认 52px + 修正值) | | - | - | - | | default | 56px | 52px | | comfortable | 54px | 50px | | compact | 52px | 48px |
height:固定表格高度
heightprop 接受数字或字符串(如"300px"),用于设置表格整体高度。示例(prop-height.vue):
<v-table height="300px"> <!-- 内容超出 300px 时,表格内部滚动 --> </v-table>底层实现:设置 height 后,组件会额外追加v-table--fixed-height类(VTable.tsx),并将高度值通过convertToUnit转为 CSS 长度应用到.v-table__wrapper的style.height(VTable.tsx)。同时 VTable.sass 为v-table--fixed-height设置了overflow-y: auto,实现内容溢出时仅表格区域滚动。
fixed-header:固定表头
fixed-headerprop 需与height配合使用,将表头固定在表格顶部,滚动内容时表头保持可见。示例(prop-fixed-header.vue):
<v-table height="300px" fixed-header> <!-- 表头固定,tbody 内容滚动 --> </v-table>底层实现:这里用到了 CSSposition: sticky,见 VTable.sass:
.v-table--fixed-header > .v-table__wrapper > table > thead position: sticky top: 0 z-index: 2同时表头单元格会获得background: $table-background与box-shadow: inset 0 -1px 0 $table-border-color(VTable.sass),保证滚动时表头不透明且与内容区有清晰分隔线。z-index: 2确保表头始终覆盖在滚动的行内容之上。
striped:斑马纹
stripedprop 为表格行添加交替背景色,取值为'even'或'odd',分别对应偶数行、奇数行着色。示例(prop-striped.vue):
<v-table striped="even"> <!-- 偶数行应用条纹背景 --> </v-table>底层实现:源码中striped的 validator 只接受'even'与'odd'(VTable.tsx),渲染时对应追加v-table--striped-even或v-table--striped-odd类(VTable.tsx)。样式通过nth-child(even/odd)选择器实现(VTable.sass):
.v-table--striped-even > .v-table__wrapper > table > tbody > tr:nth-child(even) background-image: linear-gradient(0deg, $table-stripe-color, $table-stripe-color)条纹颜色由 Sass 变量$table-stripe-color控制,默认值为rgba(var(--v-border-color), var(--v-hover-opacity))(_variables.scss)。官方文档特别提示:条纹颜色可通过 Sass 变量进一步调整(详见下文"通过 Sass 变量定制")。
其他 Props
源码中还提供了文档示例之外的一些 Props,一并说明:
| Prop | 类型 | 默认值 | 说明 | | - | - | - | - | |gridlines|Boolean \| 'horizontal' \| 'vertical' \| 'all'|'horizontal'| 表格网格线方向。传true等价于'all'(横竖都有),传false则无网格线('none')。校验逻辑见 VTable.tsx | |fixed-footer|Boolean|false| 固定表尾(<tfoot>),与fixed-header对称,同样基于position: sticky; bottom: 0(VTable.sass) | |hover|Boolean|false| 行悬停高亮。实现上通过td::after绝对定位覆盖层叠加$table-hover-color(VTable.sass),因此不会影响单元格内容 | |tag|String|'div'| 根元素标签,来自makeTagProps,默认渲染为div包裹table| |class/style| - | - | 来自makeComponentProps,透传到根元素 |
Slots 全解析
VTableSlots类型定义了 5 个插槽(VTable.tsx):
| 插槽 | 说明 | 渲染位置 | | - | - | - | |default| 表格主体内容(<thead>、<tbody>、<tfoot>等),渲染进原生<table>内部 |.v-table__wrapper > table| |caption| 表格标题,渲染进<table>内的<caption>位置 |table内部最前 | |top| 表格顶部扩展区,渲染在 wrapper 之前 | 根元素下、wrapper 外 | |bottom| 表格底部扩展区,渲染在 wrapper 之后 | 根元素下、wrapper 外 | |wrapper| 自定义整个 wrapper 区域,仅在未提供default插槽时生效 | 替代.v-table__wrapper|
从 VTable.tsx 的渲染逻辑可见,当存在top/bottom插槽时,组件会自动追加v-table--has-top/v-table--has-bottom类(VTable.sass),将 wrapper 的对应圆角清零,保证顶部/底部区域与表格区视觉上融为一体。
典型用法:用top插槽放工具栏(搜索框、操作按钮),用bottom插槽放分页或摘要信息:
<v-table> <template #top> <div class="pa-4">表格工具栏</div> </template> <thead>…</thead> <tbody>…</tbody> <template #bottom> <div class="pa-4">共 10 条记录</div> </template> </v-table>通过 Sass 变量定制
官方文档明确指出 striped 的配色"can be further adjusted using sass variables"(可通过 Sass 变量进一步调整)。实际上v-table的全部视觉细节都集中定义在 _variables.scss 中,支持在项目中覆盖:
| Sass 变量 | 默认值 | 作用 | | - | - | - | |$table-background|rgb(var(--v-theme-surface))| 表格背景色,随主题变量联动 | |$table-color|theme-color('on-surface', var(--v-high-emphasis-opacity))| 文字颜色 | |$table-density|('default': 0, 'comfortable': -2, 'compact': -4)| 三种密度对应的行高/表头高修正值 | |$table-header-height|56px| 表头高度基准值 | |$table-header-font-weight|500| 表头字重 | |$table-row-height|52px| 行高基准值 | |$table-border-color|rgba(var(--v-border-color), var(--v-border-opacity))| 网格线/边框颜色 | |$table-border|thin solid $table-border-color| 边框样式 | |$table-hover-color|rgba(var(--v-border-color), var(--v-hover-opacity))| 悬停高亮色 | |$table-stripe-color|rgba(var(--v-border-color), var(--v-hover-opacity))| 斑马纹颜色 | |$table-transition-duration|0.28s| 过渡动画时长 | |$table-line-height|1.5| 行高(line-height) | |$table-column-padding|0 16px| 单元格内边距 |
覆盖方式是在你的全局样式中、引入 Vuetify 样式之前重新赋值,例如:
// 自定义 v-table 变量 $table-stripe-color: rgba(99, 102, 241, 0.08); $table-header-font-weight: 600; $table-column-padding: 0 24px; // 之后再引入 Vuetify 样式 @use 'vuetify' with (...)所有变量均带!default声明,因此可以被安全覆盖而不会报重复定义错误。表格过渡动画的时长、属性与缓动函数($table-transition-duration/$table-transition-property/$table-transition-timing-function)默认作用于box-shadow, opacity, background, height,在斑马纹、悬停等状态切换时提供平滑过渡(VTable.sass)。
源码实现要点:渲染结构与可访问性
从 VTable.tsx 可以提炼几个值得注意的实现细节:
根元素为 div,table 包在 wrapper 中:
v-table根元素默认是div(flex 纵向布局,max-width: 100%),内部.v-table__wrapper承担滚动容器职责(overflow: auto,VTable.sass)。这样做的好处是:固定高度时滚动发生在 wrapper 层,而表头 sticky 定位与圆角裁剪都能精确控制。gridlines 的归一化处理:
gridlines为布尔值时会被归一化为'all'(true)或'none'(false),最终以v-table--gridlines-{none|horizontal|vertical|all}类名输出(VTable.tsx),水平网格线作用于th的border-bottom与行间border-bottom,垂直网格线作用于th:not(:last-child)/td:not(:last-child)的border-right(VTable.sass)。aria-label 透传:组件通过
pickWithRest(attrs, [/^aria-label/])将aria-label属性单独提取并透传到原生<table>元素上(VTable.tsx),其余属性落在根元素上。这意味着无障碍标注可以精准作用于语义化表格本体:<v-table aria-label="月度销售数据"> … </v-table>主题与密度的复用:
theme与density均来自 Vuetify 通用 composables(provideTheme/useDensity),与全组件库的密度、主题体系完全统一,因此v-table可以无缝嵌入不同主题的应用而无需额外配置。
小结与选型建议
v-table的设计哲学是"轻":原生表格结构 + 精选的视觉增强 Props。适合以下场景:
- 静态或仅需展示的数据列表,无需排序、筛选、分页;
- 需要固定表头、固定高度滚动、斑马纹、悬停高亮等视觉特性的纯展示表格;
- 希望用最小改动把现有 HTML 表格升级为 Material Design 风格。
而当你需要列排序、分页、服务端数据加载、行选择等能力时,应升级到v-data-table系列组件。在 Vuetify 生态中,v-table与v-data-table分别覆盖"轻量展示"与"数据密集型"两类需求,配合使用即可应对绝大多数表格场景。
进一步阅读当前仓库中的相关资源:
- 组件源码:VTable.tsx
- 组件样式:VTable.sass
- 样式变量:_variables.scss
- 官方文档原文:tables.md
- 全部官方示例:packages/docs/src/examples/v-table(含 usage、prop-dark、prop-dense、prop-height、prop-fixed-header、prop-striped 六个示例)
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考