Vant Cell 单元格组件完全指南:从基础用法到源码级原理解析
【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant
Cell(单元格)是 Vant 移动端 UI 库中最基础也最高频的列表展示组件,常用于信息展示、表单入口与页面导航。本文以 Cell 官方文档 为核心,完整覆盖其引入方式、全部 Props/Slots/Events 配置、CSS 变量主题定制,并结合 Cell.tsx 源码、CellGroup.tsx 源码 与 测试用例 深入剖析其实现原理,帮助你从"会用"进阶到"用得明白"。
介绍与引入
单元格(Cell)是列表中的单个展示项,通常由左侧标题、右侧内容、可选描述信息(label)、图标与箭头构成。它可以单独使用,也可以与CellGroup搭配组成分组列表。
全局注册组件的方式如下(更多注册方式可参考 advanced-usage 组件注册章节):
import { createApp } from 'vue'; import { Cell, CellGroup } from 'vant'; const app = createApp(); app.use(Cell); app.use(CellGroup);从源码看,注册时组件会被withInstall包装,并声明了全局组件名VanCell(见 cell/index.ts),因此模板中可直接使用<van-cell>与<van-cell-group>,无需额外引入。
基础用法与卡片风格
Cell可以单独使用,也可以与CellGroup搭配使用,CellGroup可以为Cell提供上下外边框:
<van-cell-group> <van-cell title="单元格" value="内容" /> <van-cell title="单元格" value="内容" label="描述信息" /> </van-cell-group>通过CellGroup的inset属性,可以将单元格转换为圆角卡片风格(从 3.1.0 版本开始支持):
<van-cell-group inset> <van-cell title="单元格" value="内容" /> <van-cell title="单元格" value="内容" label="描述信息" /> </van-cell-group>边框的实现原理
查看 CellGroup.tsx 源码可以发现,普通模式下CellGroup通过BORDER_TOP_BOTTOM工具类为整个分组添加上下边框;而inset模式下则不再使用该边框类,改由卡片自身的圆角与留白呈现独立分组效果。同时 index.less 中每个.van-cell通过::after伪元素(hairline-bottom混合宏)绘制细分割线,且最后一个单元格(:last-child)与--borderless样式会隐藏该分割线——这就是为什么分组内相邻单元格之间只有一条纤细边框的底层原因。
单元格大小
通过size属性可以控制单元格的大小,可选值为normal(默认)与large:
<van-cell title="单元格" value="内容" size="large" /> <van-cell title="单元格" value="内容" size="large" label="描述信息" />size的类型定义在源码中为export type CellSize = 'normal' | 'large'(见 Cell.tsx)。large尺寸对应的样式变量包括--van-cell-large-vertical-padding(垂直内边距)、--van-cell-large-title-font-size(标题字号)、--van-cell-large-label-font-size(描述字号)等,可参考下方"主题定制"章节统一调整。
展示图标与箭头
左侧图标
通过icon属性在标题左侧展示图标,图标名称与 Icon 组件 的name属性一致(支持内置图标名或图片链接),也可通过icon-prefix自定义图标类名前缀:
<van-cell title="单元格" icon="location-o" />从源码 Cell.tsx 可以看到,当传入icon属性且未提供icon插槽时,组件内部会渲染一个Icon组件并应用van-cell__left-icon类;icon-prefix会透传给 Icon 组件的class-prefix属性。测试用例也验证了icon-prefix="my-icon"能正确生效(见 test/index.spec.ts)。
右侧箭头
设置is-link属性后会在单元格右侧显示箭头,并且可以通过arrow-direction属性控制箭头方向(可选up/down/left,默认right):
<van-cell title="单元格" is-link /> <van-cell title="单元格" is-link value="内容" /> <van-cell title="单元格" is-link arrow-direction="down" value="内容" />源码中renderRightIcon(Cell.tsx)的逻辑值得注意:当arrow-direction不是默认的right时,会使用arrow-${direction}图标名(如arrow-down),否则使用arrow。箭头图标颜色由--van-cell-right-icon-color变量控制。
点击反馈与无障碍
is-link不仅展示箭头,还会自动开启点击反馈:源码中const clickable = props.clickable ?? isLink;(Cell.tsx)表示clickable默认继承is-link的值,且当clickable为真时,根节点会附加role="button"与tabindex="0"(Cell.tsx),对屏幕阅读器与键盘操作友好。若你只想显示箭头而不想要点击态,可显式传入:clickable="false",测试用例中已覆盖该场景(test/index.spec.ts)。
页面导航
可以通过url属性进行 URL 跳转,或通过to属性进行路由跳转:
<van-cell title="URL 跳转" is-link url="https://github.com" /> <van-cell title="路由跳转" is-link to="index" />导航底层实现
Vant 将跳转逻辑抽取为独立的route函数(见 composables/use-route.ts),to、url、replace三个属性来自routeProps。其执行顺序为:
- 优先判断
to且当前环境存在 Vue Router 实例,此时调用router.push(to)(若replace为true则调用router.replace(to))进行路由跳转,to的类型即 Vue Router 的RouteLocationRaw(string | object); - 否则若传入
url,则通过location.href = url(或location.replace(url))进行浏览器地址跳转。
Cell将routeProps通过extend合并进自身 props(Cell.tsx),并在onClick时调用route。这意味着:只有设置了is-link(或clickable)时,点击才会触发导航,这是源码层面确认的行为。
分组标题
通过CellGroup的title属性可以指定分组标题,也可以使用title插槽完全自定义标题内容:
<van-cell-group title="分组1"> <van-cell title="单元格" value="内容" /> </van-cell-group> <van-cell-group title="分组2"> <van-cell title="单元格" value="内容" /> </van-cell-group>从 CellGroup.tsx 源码可见,当title属性或title插槽存在时,渲染结果会拆分为"标题节点 + 分组容器节点"两个部分,标题样式类为van-cell-group__title,其内边距、字号与颜色均可通过下方样式变量定制。
使用插槽自定义内容
当属性无法满足需求时,可以使用插槽来自定义任意区域的内容:
<van-cell value="内容" is-link> <!-- 使用 title 插槽来自定义标题 --> <template #title> <span class="custom-title">单元格</span> <van-tag type="primary">标签</van-tag> </template> </van-cell> <van-cell title="单元格" icon="shop-o"> <!-- 使用 right-icon 插槽来自定义右侧图标 --> <template #right-icon> <van-icon name="search" class="search-icon" /> </template> </van-cell> <style> .custom-title { margin-right: 4px; vertical-align: middle; } .search-icon { font-size: 16px; line-height: inherit; } </style>Cell共提供 6 个插槽:title、value、label、icon、right-icon、extra。源码层面有三个值得注意的实现细节:
value与default是别名关系:renderValue中const slot = slots.value || slots.default;(Cell.tsx),即不具名内容默认渲染在右侧区域;title插槽支持动态清空:当title插槽渲染结果为空数组时直接返回(Cell.tsx),这是为了配合 Field 组件动态设置空 label 的需求;extra插槽渲染在结构最右侧(Cell.tsx),适合放置按钮、徽标等附加操作元素。
垂直居中
通过center属性可以让Cell的左右内容都垂直居中,适合标题与描述信息较多、行高不一的场景:
<van-cell center title="单元格" value="内容" label="描述信息" />该属性在渲染时被写入根节点的van-cell--center类,对应 index.less 中的align-items: center样式。
API 一览
CellGroup Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| title | 分组标题 | string | - |
| inset | 是否展示为圆角卡片风格 | boolean | false |
| border | 是否显示外边框 | boolean | true |
Cell Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| title | 左侧标题 | number | string | - |
| value | 右侧内容 | number | string | - |
| label | 标题下方的描述信息 | number | string | - |
| size | 单元格大小,可选值为largenormal | string | - |
| icon | 左侧图标名称或图片链接,等同于 Icon 组件的 name 属性(见 Icon 文档) | string | - |
| icon-prefix | 图标类名前缀,等同于 Icon 组件的 class-prefix 属性 | string | van-icon |
| tag | 根节点对应的 HTML 标签名 | string | div |
| url | 点击后跳转的链接地址 | string | - |
| to | 点击后跳转的目标路由对象,等同于 Vue Router 的to属性(类型为RouteLocationRaw,支持字符串或对象) | string | object | - |
| border | 是否显示内边框 | boolean | true |
| replace | 是否在跳转时替换当前页面历史 | boolean | false |
| clickable | 是否开启点击反馈 | boolean | null(默认跟随is-link) |
| is-link | 是否展示右侧箭头并开启点击反馈 | boolean | false |
| required | 是否显示表单必填星号 | boolean | false |
| center | 是否使内容垂直居中 | boolean | false |
| arrow-direction | 箭头方向,可选值为leftupdown | string | right |
| title-style | 左侧标题额外样式 | string | Array | object | - |
| title-class | 左侧标题额外类名 | string | Array | object | - |
| value-class | 右侧内容额外类名 | string | Array | object | - |
| label-class | 描述信息额外类名 | string | Array | object | - |
源码补充:
title、value、label均为numericProp(数字或字符串皆可);border使用truthProp默认值为true;clickable与required的类型均为boolean | null(Cell.tsx)。tag属性支持任意合法 HTML 标签名,测试中验证了tag="a"的渲染结果(test/index.spec.ts)。
Cell Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| click | 点击单元格时触发 | event: MouseEvent |
CellGroup Slots
| 名称 | 说明 |
|---|---|
| default | 默认插槽 |
| title | 自定义分组标题 |
Cell Slots
| 名称 | 说明 |
|---|---|
| title | 自定义左侧标题 |
| value | 自定义右侧内容(default插槽是其别名) |
| label | 自定义标题下方的描述信息 |
| icon | 自定义左侧图标 |
| right-icon | 自定义右侧图标 |
| extra | 自定义单元格最右侧的额外内容 |
类型定义
组件导出以下类型定义:
import type { CellSize, CellProps, CellGroupProps, CellArrowDirection, } from 'vant';对应源码中:CellSize、CellArrowDirection、CellProps定义于 cell/Cell.tsx,CellGroupProps定义于 cell-group/CellGroup.tsx,统一在 cell/index.ts 中对外导出。
主题定制:CSS 变量与 ConfigProvider
Cell与CellGroup提供了丰富的 CSS 变量,可结合 ConfigProvider 组件 在全局或局部统一覆盖,实现品牌化主题。完整变量表如下:
| 名称 | 默认值 | 描述 |
|---|---|---|
| --van-cell-font-size | var(--van-font-size-md) | 单元格字号 |
| --van-cell-line-height | 24px | 单元格行高 |
| --van-cell-vertical-padding | 10px | 垂直内边距 |
| --van-cell-horizontal-padding | var(--van-padding-md) | 水平内边距 |
| --van-cell-text-color | var(--van-text-color) | 文本颜色 |
| --van-cell-background | var(--van-background-2) | 背景色 |
| --van-cell-border-color | var(--van-border-color) | 分割线颜色 |
| --van-cell-active-color | var(--van-active-color) | 点击态背景色 |
| --van-cell-required-color | var(--van-danger-color) | 必填星号颜色 |
| --van-cell-label-color | var(--van-text-color-2) | 描述信息颜色 |
| --van-cell-label-font-size | var(--van-font-size-sm) | 描述信息字号 |
| --van-cell-label-line-height | var(--van-line-height-sm) | 描述信息行高 |
| --van-cell-label-margin-top | var(--van-padding-base) | 描述信息上边距 |
| --van-cell-value-color | var(--van-text-color-2) | 右侧内容颜色 |
| --van-cell-value-font-size | inherit | 右侧内容字号 |
| --van-cell-icon-size | 16px | 图标尺寸 |
| --van-cell-right-icon-color | var(--van-gray-6) | 右侧箭头颜色 |
| --van-cell-large-vertical-padding | var(--van-padding-sm) | large 尺寸垂直内边距 |
| --van-cell-large-title-font-size | var(--van-font-size-lg) | large 尺寸标题字号 |
| --van-cell-large-label-font-size | var(--van-font-size-md) | large 尺寸描述字号 |
| --van-cell-large-value-font-size | inherit | large 尺寸内容字号 |
| --van-cell-group-background | var(--van-background-2) | 分组背景色 |
| --van-cell-group-title-color | var(--van-text-color-2) | 分组标题颜色 |
| --van-cell-group-title-padding | var(--van-padding-md) var(--van-padding-md) var(--van-padding-xs) | 分组标题内边距 |
| --van-cell-group-title-font-size | var(--van-font-size-md) | 分组标题字号 |
| --van-cell-group-title-line-height | 16px | 分组标题行高 |
| --van-cell-group-inset-padding | 0 var(--van-padding-md) | 卡片风格分组内边距 |
| --van-cell-group-inset-radius | var(--van-radius-lg) | 卡片风格圆角 |
| --van-cell-group-inset-title-padding | var(--van-padding-md) var(--van-padding-md) var(--van-padding-xs) var(--van-padding-xl) | 卡片风格分组标题内边距 |
这些变量的默认值定义在 cell/index.less,并在类型层面对应CellThemeVars(见 cell/types.ts),供使用 TypeScript 的开发者获得变量名的智能提示。
例如,在项目入口通过 ConfigProvider 全局放大单元格的舒适度:
<van-config-provider :theme-vars="{ cellVerticalPadding: '14px', cellHorizontalPadding: '16px', cellFontSize: '16px', cellGroupInsetRadius: '12px', }" > <!-- 应用内容 --> </van-config-provider>与其它 Vant 组件的组合
Cell在设计上是 Vant 内部大量组件的"底盘":Field、CouponCell、ContactCard、AddressList等组件均复用了cellSharedProps与.van-cell样式体系(该共享 props 同样定义于 Cell.tsx)。因此深入理解Cell的 Props、插槽与样式变量体系,有助于举一反三地掌握这些上层组件的行为,例如required星号、center对齐、size尺寸等属性在很多派生组件中语义一致。
完整的交互演示可直接查看 cell/demo/index.vue,其中覆盖了本文介绍的全部用法场景;组件的行为契约则由 cell/test/index.spec.ts 中的 12 个测试用例(插槽渲染、箭头方向、title-style、icon-prefix、clickable 关闭、tag 自定义等)固化保障。
【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考