# Vant 设计系统

## Vant 设计系统界面预览

选择收件人、编辑地址、验证新条目，并切换原生组件主题。

## Vant 设计系统设计参考

Vant 4.10.2 CSS 变量，读取自已安装的基础样式表。预览通过 ConfigProvider 覆盖为原创的青绿色主色；下方明确标注了默认角色。

### 默认颜色角色

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --van-primary-color | var(--van-blue) | 默认操作别名；蓝色为 #1989fa。 |
| --van-success-color | var(--van-green) | 成功别名；绿色为 #07c160。 |
| --van-danger-color | var(--van-red) | 危险别名；红色为 #ee0a24。 |
| --van-warning-color | var(--van-orange) | 警告别名；橙色为 #ff976a。 |
| --van-text-color | var(--van-gray-8) | 主要文本别名；gray-8 为 #323233。 |
| --van-text-color-2 | var(--van-gray-6) | 次要文本别名；gray-6 为 #969799。 |
| --van-border-color | var(--van-gray-3) | 分隔线别名；gray-3 为 #ebedf0。 |
| --van-background | var(--van-gray-1) | 页面表面；gray-1 为 #f7f8fa。 |
| --van-background-2 | var(--van-white) | 组件表面；白色为 #fff。 |
### 内边距比例

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --van-padding-base | 4px | 精细的内部偏移。 |
| --van-padding-xs | 8px | 较小的内部间距。 |
| --van-padding-sm | 12px | 地址条目内边距。 |
| --van-padding-md | 16px | 常规页面内边距。 |
| --van-padding-lg | 24px | 区块内边距。 |
| --van-padding-xl | 32px | 较大的页面内边距。 |
### 排版与形状

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --van-font-size-xs | 10px | 默认 UI 字号。 |
| --van-font-size-sm | 12px | 默认 UI 字号。 |
| --van-font-size-md | 14px | 默认 UI 字号。 |
| --van-font-size-lg | 16px | 默认 UI 字号。 |
| --van-line-height-xs | 14px | 对应的行高令牌。 |
| --van-line-height-sm | 18px | 对应的行高令牌。 |
| --van-line-height-md | 20px | 对应的行高令牌。 |
| --van-line-height-lg | 22px | 对应的行高令牌。 |
| --van-radius-sm | 2px | 命名圆角半径。 |
| --van-radius-md | 4px | 命名圆角半径。 |
| --van-radius-lg | 8px | 命名圆角半径。 |
| --van-radius-max | 999px | 命名圆角半径。 |
| --van-disabled-opacity | .5 | 默认禁用状态不透明度。 |
| --van-duration-base | .3s | 标准过渡时长。 |
### 地址列表与预览调整

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --van-address-list-padding | 12px 12px 80px | 官方默认值会为底部的添加按钮预留空间。 |
| themeVars.addressListPadding | 12px | 本预览隐藏了固定添加按钮，因此进行了原创调整。 |
| themeVars.primaryColor | #176b77 | 映射到 --van-primary-color 的原创主色覆盖。 |
| --van-address-list-item-font-size | 13px | 官方地址文字字号。 |
| --van-address-list-edit-icon-size | 20px | 官方编辑图标尺寸；不代表整个触控区域的大小。 |
## Vant 设计系统完整指南

实用指南，介绍如何为真实界面选择、应用和评审此系统。

完整指导、实现起点和源代码链接。

## Vant 设计系统移动组件：明确标注 CSS 角色

### 移动组件：明确标注 CSS 角色

> Vant 面向 Vue 移动 Web 界面。其 AddressList、Field 和 CellGroup 提供紧凑的收件地址行与表单单元格，而非桌面管理表格。Sample-kit 流程使用这些原生组件，并在单独的摘要中清晰显示所选地址。

主色角色默认通过 --van-primary-color 使用蓝色。成功、危险和警告状态各自引用不同的颜色变量。此示例有意通过 ConfigProvider 将主色改为 #176b77；并未将这种青绿色称为官方 Vant 品牌色。原创纸张纹理插画仅作装饰，不承载任何控件状态。

阅读配套规范

## Vant 设计系统：四像素内边距比例与紧凑字体

### 四像素内边距比例与紧凑字体

Vant 提供 4、8、12、16、24 和 32 像素的内边距值。这些都是真实的基础变量，并非根据截图推测得出。地址列表项使用较小的内边距令牌，外围预览则通过更大的区块间距，让表单和订单摘要清晰区分。

命名文本字号范围为 10 至 16 像素，对应的行高为 14 至 22 像素。地址文本使用独立的 13px 组件变量。移动端产品的正文可能需要比这些控件默认值更大的字号：示例标题原始字号为 32px，在页面断点处缩小为 27px。

阅读配套规范

## Vant 设计系统：地址 ID 驱动单选项

### 通过地址 ID 驱动单选项选择

AddressList 接收包含 id、name、tel、address 和可选 isDefault 字段的列表记录。其 v-model 值用于标识选中的记录。摘要通过在当前列表中查找该 ID 计算得出，因此编辑收件人后，显示的收货地址会立即更新，无需另行维护独立的摘要状态。

不可用的仓库通过 disabled-list 传入，并附有清晰的禁用状态说明。它仍会显示，方便用户了解情况，但无法选为收货目的地。Default 徽标表示该记录是默认项；它与当前选中状态相互独立，不会仅因选择了另一个单选项而改变。

阅读配套规范

## Vant 设计系统：草稿与已保存记录分开管理

### 将草稿与已保存记录分开

编辑事件会提供地址记录。编辑器只将其中可编辑的字段复制到响应式草稿中，并单独保存稳定 ID。取消操作会隐藏草稿，不会修改已保存的地址。保存时会替换匹配的记录，或追加一条新的本地记录，然后选中该 ID。

此示例将编辑器呈现在列表下方，而不是打开底部弹窗。这样，即使嵌入文档，也能完整使用整个示例。Vant 还提供 AddressEdit，用于统一的地址录入；本示例使用 Form 和 Field，是因为示例地址特意避免假定某个国家的行政区划数据。

1. 选择一间工作室，并在打开编辑器前检查摘要。

2. 更改收件人，然后取消，以确认已保存的列表项未发生变化。

3. 再次打开编辑器，保存有效字段，并检查选中项的摘要。

阅读配套规范

## Vant 设计系统：字段规则控制提交事件

### 字段规则控制提交事件

Form 使用 validate-trigger="onSubmit"。收件人验证器会去除空白字符，并要求至少包含两个字符。电话号码验证器允许一定范围内的数字、空格、括号和连字符，也允许以加号开头。地址验证器要求至少包含十个非空白字符。这些检查仅用于演示机制，并不等同于邮政地址验证或通用电话号码验证。

设置 native-type="submit" 的主按钮会提交原生表单。Vant 仅在规则通过后才会触发 submit 事件。错误信息会显示在相应字段旁，scroll-to-error 会将无效字段滚动到可视区域。预览还会在开始编辑时将焦点移至第一个收件人输入框。验证失败时，草稿会保留。

阅读配套规范

## Vant 设计系统：ConfigProvider 将驼峰命名值映射到 CSS 变量

### ConfigProvider 将驼峰式值映射为 CSS 变量

theme-vars 对象包含 primaryColor、buttonPrimaryBackground、buttonPrimaryBorderColor 和 addressListPadding。ConfigProvider 会将这些名称映射到对应的 --van-* 变量。在此独立文档中，provider 使用 theme-vars-scope="global"，这样，在根节点声明的别名就会根据更改后的主色角色解析。覆盖该角色以及两个主按钮值，可让原生操作按钮与单选项保持协调一致。

在 light 和 dark 之间切换 theme 属性，会更新 Vant 的组件主题。页面仍需使用主题变量自行设置背景和文本样式；仅设置 provider 并不会为应用中的每个元素应用颜色。装饰性纸张样例在两种主题下均保留其材质颜色。

阅读配套规范

## Vant 设计系统：固定的移动端操作需要考虑嵌入方式

### 固定的移动端操作需要考虑嵌入方式

AddressList 通常会在底部预留 80 像素内边距，用于容纳固定的添加按钮。此预览将 show-add-button 设为 false，并提供一个普通的流内 Button。同时将 addressListPadding 改为 12 像素，避免在嵌入示例中出现脱离内容的固定操作按钮，也避免底部留下无法解释的空白区域。

在宽屏上，列表和物料摘要分为两列。低于原有的 680px 断点时，两者会改为上下排列。系统会显式将原生 AddressList 的 height:100% 重置为 height:auto，使面板随内容调整高度，而不会与下一个网格行重叠。不使用全局最小视口高度，因此父页面可以根据内容调整嵌入文档的尺寸。地址名称会在窄屏上换行，不会撑宽页面。

阅读配套规范

## Vant 设计系统：可见焦点与明确的本地结果

### 可见焦点与明确的本地结果

Vant 基础重置样式会移除默认焦点轮廓。配套的页面样式表会为按钮、输入框、文本区域和带 tabindex 的控件恢复 3 像素的 focus-visible 焦点环。这是应用层面的补充，并不意味着仅导入库就完成了无障碍工作。主题切换控件带有无障碍名称和可见标签。

状态提示会记录本地保存或目的地选择，并明确说明尚未预订配送。此示例没有结账端点、存储功能或外部副作用。真实结账流程需要在购买前进行服务器端地址验证、配送资格检查和最终确认。

- 对不可用的地址，应明确显示原因，而不是悄然删除。

- 提交无效内容后保留草稿，方便用户更正有误字段。

- 说明操作是更改本地选中项，还是实际预订配送。

阅读配套规范

## Vant 设计系统：导入区域设置与组件样式

### 导入语言环境与组件样式

完整的 SFC 在本地导入其组件。入口文件通过 Locale.use 安装英文区域设置，并在原始布局样式表之前导入 vant/lib/index.css。已验证的版本为 Vant 4.10.2，搭配 Vue 3；英文区域设置导入路径中的 .mjs 后缀与已安装的 ESM 文件一致。

独立预览将其 JavaScript、CSS 和图标字体打包到文档中。在保留打包的 WOFF2 字体后，预览会移除未使用的远程 WOFF 备用字体，因此示例无需请求第三方字体。生产应用应使用自己的打包工具和资源策略，而不是照搬托管演示的 URL。

阅读配套规范

## Vant 设计系统：组件示例

### 地址选择与验证后编辑

完整的 Vue SFC，使用 AddressList、Form、Field、ConfigProvider 和受控草稿。

```
<script setup>
import {ref,reactive,computed,nextTick} from 'vue';
import {ConfigProvider,AddressList,Button,Form,Field,CellGroup,Tag,Switch,NoticeBar} from 'vant';
const list=ref([{id:'studio',name:'Alex Morgan',tel:'+44 20 7946 0101',address:'Studio 4, 18 Paper Street, London',isDefault:true},{id:'workshop',name:'Jules Chen',tel:'+44 20 7946 0122',address:'Workshop B, 52 Clay Road, London'}]);
const disabledList=[{id:'archive',name:'Sam Rivera',tel:'+44 20 7946 0133',address:'Old warehouse, 8 Mill Lane, London'}];
const chosen=ref('studio'),editing=ref(false),editingId=ref(null),notice=ref(''),dark=ref(false),formRef=ref();
const draft=reactive({name:'',tel:'',address:''});
const selected=computed(()=>list.value.find(x=>x.id===chosen.value));
const themeVars={primaryColor:'#176b77',addressListPadding:'12px',buttonPrimaryBackground:'#176b77',buttonPrimaryBorderColor:'#176b77'};
async function edit(item){editingId.value=item?.id||null;Object.assign(draft,item?{name:item.name,tel:item.tel,address:item.address}:{name:'',tel:'',address:''});editing.value=true;notice.value='';await nextTick();formRef.value?.resetValidation();document.querySelector('[name="recipient"]')?.focus();}
function save(){const value={id:editingId.value||`local-${Date.now()}`,name:draft.name.trim(),tel:draft.tel.trim(),address:draft.address.trim()};if(editingId.value)list.value=list.value.map(x=>x.id===editingId.value?{...x,...value}:x);else list.value.push(value);chosen.value=value.id;editing.value=false;notice.value='Address saved in this local preview.';}
function confirm(){notice.value=`Selected ${selected.value.name} at ${selected.value.address}. No delivery was booked.`;}
const nonempty=v=>v.trim().length>=2;
const phone=v=>/^\+?[\d ()-]{7,22}$/.test(v.trim());
</script>
<template><ConfigProvider theme-vars-scope="global" :theme="dark?'dark':'light'" :theme-vars="themeVars"><main class="delivery" :class="{dark}"><header><div><p class="eyebrow">VANT · MOBILE COMMERCE</p><h1>A destination for your sample kit.</h1><p class="intro">Choose a studio, update a recipient or add a local address.</p></div><label class="mode"><span>Dark</span><Switch v-model="dark" size="22px" aria-label="Dark theme" /></label></header><div class="columns"><section class="address-panel" aria-label="Delivery addresses"><div class="section-heading"><h2>Delivery address</h2><Tag plain type="primary">{{list.length}} available</Tag></div><AddressList v-model="chosen" :list="list" :disabled-list="disabledList" disabled-text="Outside the sample delivery area" default-tag-text="Default" :show-add-button="false" @edit="edit" @select="notice=''" /><div class="actions"><Button plain block type="primary" @click="edit()">Add a local address</Button></div></section><aside><section class="kit"><div class="paper-samples" aria-hidden="true"><i></i><i></i><i></i></div><p class="eyebrow">MATERIAL LIBRARY</p><h2>Paper & pigment kit</h2><p>Six paper stocks. Three print finishes. One place to compare them.</p><dl><div><dt>Recipient</dt><dd>{{selected?.name}}</dd></div><div><dt>Destination</dt><dd>{{selected?.address}}</dd></div></dl><Button block type="primary" @click="confirm">Use this address</Button><p class="local-note">Selection only. Nothing is purchased or shipped.</p></section></aside></div><section v-if="editing" class="editor"><h2>{{editingId?'Edit recipient':'Add an address'}}</h2><Form ref="formRef" validate-trigger="onSubmit" label-align="top" scroll-to-error @submit="save"><CellGroup inset><Field v-model="draft.name" name="recipient" label="Recipient" placeholder="Full name" :rules="[{validator:nonempty,message:'Enter at least two characters.'}]" /><Field v-model="draft.tel" name="telephone" type="tel" label="Telephone" placeholder="+44 20 7946 0100" :rules="[{validator:phone,message:'Use 7–22 characters: digits, spaces, +, brackets or hyphens.'}]" /><Field v-model="draft.address" name="address" type="textarea" rows="2" autosize label="Address" placeholder="Building, street and city" :rules="[{validator:v=>v.trim().length>=10,message:'Enter a complete address of at least ten characters.'}]" /></CellGroup><div class="form-actions"><Button type="primary" native-type="submit">Save locally</Button><Button native-type="button" @click="editing=false">Cancel</Button></div></Form></section><NoticeBar v-if="notice" wrapable :scrollable="false" color="var(--van-primary-color)" background="var(--van-background-2)" class="result" role="status">{{notice}}</NoticeBar></main></ConfigProvider></template>
```

代码参考

- 选中值是地址 ID，而不是数组中的位置。

- 隐藏固定定位的 AddressList 添加按钮；使用文档流中的 Button 打开编辑器。

- 只有在 Field 验证器通过后，才会提交表单。

### 响应式页面与可见焦点

原有的桌面双栏布局会折叠为移动端配送流程。

```
*{box-sizing:border-box}body{margin:0;background:#f7f8fa;color:#323233}.delivery{padding:32px;max-width:1080px;margin:auto;background:var(--van-background);color:var(--van-text-color)}.delivery.dark{background:var(--van-background);color:var(--van-text-color)}header{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:32px}.eyebrow{font-size:11px;font-weight:600;letter-spacing:.12em;color:var(--van-text-color-2)}h1{font-size:32px;line-height:1.2;margin:12px 0;max-width:550px}h2{font-size:18px;line-height:24px;margin:0 0 12px}.intro{font-size:15px;line-height:24px;color:var(--van-text-color-2)}.mode{display:flex;gap:8px;align-items:center;font-size:12px}.columns{display:grid;grid-template-columns:1.25fr 1fr;gap:24px}.section-heading{display:flex;justify-content:space-between;align-items:center;padding:0 12px}.section-heading h2{margin:0}.actions{padding:0 12px}.kit{background:var(--van-background-2);padding:24px;border-radius:8px}.kit p{line-height:1.6}.paper-samples{height:130px;position:relative;display:flex;align-items:center;justify-content:center;margin-bottom:24px;background:#e9edef;border-radius:4px;overflow:hidden}.paper-samples i{height:90px;width:90px;background:#d6b59b;box-shadow:0 4px 8px #0001;transform:rotate(-12deg);margin-right:-25px}.paper-samples i:nth-child(2){background:#efdfbe;transform:rotate(2deg)}.paper-samples i:nth-child(3){background:#94adb1;transform:rotate(16deg)}dl{font-size:14px;line-height:20px;margin:24px 0}dl div{display:grid;grid-template-columns:90px 1fr;margin:12px 0;gap:12px}dt{color:var(--van-text-color-2)}dd{margin:0}.local-note{font-size:12px;color:var(--van-text-color-2);margin-bottom:0}.editor{max-width:640px;margin-top:32px}.editor h2{margin-left:16px}.form-actions{display:flex;gap:12px;margin:16px}.result{margin-top:24px;border-radius:8px}button:focus-visible,input:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:3px solid #176b77!important;outline-offset:3px}@media(max-width:680px){.delivery{padding:24px 12px}.columns{grid-template-columns:1fr}header{gap:8px;margin-bottom:24px}h1{font-size:27px}.mode{padding-top:4px}.kit{padding:20px}.paper-samples{height:110px}.van-address-item__name{white-space:normal}}

.delivery .van-address-list{height:auto}
```

代码参考

- 组件几何尺寸由 Vant 决定；680px 页面断点则由应用自行设定。

- 预览会恢复可见的焦点环，因为基础重置样式会移除默认轮廓。

## Vant 设计系统：Agent 设置

### 实现起点

已通过 Vue 3 和 Vant 4.10.2 验证。此示例不会在内存状态之外存储地址。

```
// Create the project first:
// npm create vite@latest vant-specimen -- --template vue
// cd vant-specimen && npm install
// In a Vite Vue 3 project:
// npm install vant@4.10.2
// Save the complete SFC as App.vue and the supplied layout as style.css.
import {createApp} from 'vue';
import {Locale} from 'vant';
import enUS from 'vant/es/locale/lang/en-US.mjs';
import 'vant/lib/index.css';
import './style.css';
import App from './App.vue';
Locale.use('en-US',enUS);
createApp(App).mount('#app');
// index.html must contain <div id="app"></div>.
// Keep the template index.html and replace its entry with the code above.
// npm run dev
```

### 适用于你项目的提示词

```
基于 Vant 4.10.2 sample-kit 中的地址选择器示例进行开发。保留原生 AddressList 和 Form/Field 编辑流程，用于添加或修改本地地址，包括字段验证和选中地址状态。保留 Locale 设置、en-US 模块、ConfigProvider 主题作用域，以及使 AddressList 高度适配内容的处理。取消操作不得替换现有地址；验证成功后，只更新本地地址集合。此地址示例不得声称已成功完成付款或预订配送时段。
```

## Vant 设计系统：来源与范围

Vant 4.10.2。区分默认令牌与原始页面设置。示例地址均为虚构；选择和编辑仅在本地进行。

- AddressList 地址记录结构、选择状态和禁用列表的 API。

- Form 提交/失败事件和验证规则。

- 字段 原生表单字段组合。

- ConfigProvider 主题变量和深色主题。

- 快速入门 Vue 组件和样式表配置。

- Locale 注册英文区域设置。

- 基础令牌来源 官方基础颜色、内边距、字体排印和圆角。

## Vant 设计系统：相关资源

### Vuestic UI

原生 Vuestic 评价表，采用经来源核实的浅色和深色预设、无障碍评分标签、文本区域验证、自动计算的平均分，以及可保留已完成评估的保存状态。

### Web Awesome

检查 Web Awesome 在原生自定义元素中的实际语义令牌，包括作用域内的圆角和间距调整、Shadow DOM 样式、选择控件行为和输入验证。

### Ariakit

Ariakit 提供无样式的 React 组件，具有明确的共享状态和可组合的无障碍部件。其组合框将输入的文本与提交的选择分离，使其对搜索驱动的选择器很有用；下面的参考查找器通过分组和不可用结果演示了这种区别。


- [实现参考](https://vant-ui.github.io/vant/#/en-US/address-list)
- [来源](https://github.com/youzan/vant/blob/main/packages/vant/src/style/var.less)
- [来源](https://vant-ui.github.io/vant/#/en-US/address-list)
- [阅读配套规范](https://vant-ui.github.io/vant/#/en-US/config-provider)
- [阅读配套规范](https://vant-ui.github.io/vant/#/en-US/address-list)
- [阅读配套规范](https://vant-ui.github.io/vant/#/en-US/form)
- [阅读配套规范](https://vant-ui.github.io/vant/#/en-US/quickstart)
- [代码参考](https://vant-ui.github.io/vant/#/en-US/address-list)
- [代码参考](https://vant-ui.github.io/vant/#/en-US/config-provider)
- [AddressList 地址记录结构、选择状态和禁用列表的 API。](https://vant-ui.github.io/vant/#/en-US/address-list)
- [Form 提交/失败事件和验证规则。](https://vant-ui.github.io/vant/#/en-US/form)
- [字段 原生表单字段组合。](https://vant-ui.github.io/vant/#/en-US/field)
- [ConfigProvider 主题变量和深色主题。](https://vant-ui.github.io/vant/#/en-US/config-provider)
- [快速入门 Vue 组件和样式表配置。](https://vant-ui.github.io/vant/#/en-US/quickstart)
- [Locale 注册英文区域设置。](https://vant-ui.github.io/vant/#/en-US/locale)
- [基础令牌来源 官方基础颜色、内边距、字体排印和圆角。](https://github.com/youzan/vant/blob/main/packages/vant/src/style/var.less)
