跨平台与移动端 UI · 新资源

Vant 设计系统.

使用 Vant 4 构建移动端地址选择流程:采用真实的 CSS 变量、受控的地址标识、字段验证、主题切换,以及明确的仅本地保存功能。

OpenDesign 指南9 个章节34 条参考条目原始应用指南
01

Vant 设计系统界面预览

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

Sample-kit 配送地址打开完整示例
原生 Vant 4.10.2 搭配 Vue 3。纸张插画与周边布局为原创设计。· 实现参考
02

Vant 设计系统设计参考

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

默认颜色角色

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

内边距比例

来源
名称 / 规则值 / 配置用途
--van-padding-base4px精细的内部偏移。
--van-padding-xs8px较小的内部间距。
--van-padding-sm12px地址条目内边距。
--van-padding-md16px常规页面内边距。
--van-padding-lg24px区块内边距。
--van-padding-xl32px较大的页面内边距。

排版与形状

来源
名称 / 规则值 / 配置用途
--van-font-size-xs10px默认 UI 字号。
--van-font-size-sm12px默认 UI 字号。
--van-font-size-md14px默认 UI 字号。
--van-font-size-lg16px默认 UI 字号。
--van-line-height-xs14px对应的行高令牌。
--van-line-height-sm18px对应的行高令牌。
--van-line-height-md20px对应的行高令牌。
--van-line-height-lg22px对应的行高令牌。
--van-radius-sm2px命名圆角半径。
--van-radius-md4px命名圆角半径。
--van-radius-lg8px命名圆角半径。
--van-radius-max999px命名圆角半径。
--van-disabled-opacity.5默认禁用状态不透明度。
--van-duration-base.3s标准过渡时长。

地址列表与预览调整

来源
名称 / 规则值 / 配置用途
--van-address-list-padding12px 12px 80px官方默认值会为底部的添加按钮预留空间。
themeVars.addressListPadding12px本预览隐藏了固定添加按钮,因此进行了原创调整。
themeVars.primaryColor#176b77 映射到 --van-primary-color 的原创主色覆盖。
--van-address-list-item-font-size13px官方地址文字字号。
--van-address-list-edit-icon-size20px官方编辑图标尺寸;不代表整个触控区域的大小。
03

Vant 设计系统完整指南

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

DESIGN-vant.md

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

下载指南

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

移动组件:明确标注 CSS 角色

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

摘自本 OpenDesign 指南

主色角色默认通过 --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 和受控草稿。

vue
<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 验证器通过后,才会提交表单。

响应式页面与可见焦点

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

css
*{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 页面断点则由应用自行设定。
  • 预览会恢复可见的焦点环,因为基础重置样式会移除默认轮廓。
04

Vant 设计系统:Agent 设置

实现起点

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

javascript
// 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 [email protected]
// 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

适用于你项目的提示词

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

Vant 设计系统:来源与范围

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