Vant Coupon 优惠券选择器与兑换列表(CouponList)实战指南
2026/9/12 22:55:08 网站建设 项目流程

Vant Coupon 优惠券选择器与兑换列表(CouponList)实战指南

【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant

导读

CouponList(优惠券选择器)是 Vant 移动端组件库中用于优惠券兑换与选择的核心组件,它和配套的CouponCell(优惠券单元格)一起,构成了电商下单、结算等场景下完整的一站式优惠券交互方案:单元格展示当前已选优惠券,弹出层内嵌列表完成可用券的勾选与不可用券的展示,顶部兑换栏还支持输入兑换码实时兑换新券。阅读完本篇,你将掌握CouponCell+CouponList的组合用法、全部 Props/Events/Slots 参数语义、CouponInfo数据结构的字段含义,以及底层源码的实现原理与主题定制方案。

组件介绍与引入

优惠券选择器用于优惠券的兑换和选择,它通常与优惠券单元格(CouponCell)配合使用:CouponCell负责在页面上以单元格形式展示“已选券/可选券”的金额汇总,CouponList则负责在弹层中展示可用券、不可用券两个列表并提供兑换入口。

通过以下方式全局注册组件,更多注册方式可参考组件注册:

import { createApp } from 'vue'; import { CouponCell, CouponList } from 'vant'; const app = createApp(); app.use(CouponCell); app.use(CouponList);

注册后即可在模板中直接使用<van-coupon-cell><van-coupon-list>标签。两个组件都通过 index.ts 中的withInstall包装导出,并同时注册了VanCouponList/VanCouponCell的全局组件类型,享受完整的 TypeScript 提示。

代码演示

基础用法

基础用法是一个“单元格 + 弹层”的组合模式:点击van-coupon-cell打开底部弹出层,弹出层内渲染van-coupon-list,用户勾选券或兑换新券后通过事件回调更新状态并关闭弹层:

<!-- 优惠券单元格 --> <van-coupon-cell :coupons="coupons" :chosen-coupon="chosenCoupon" @click="showList = true" /> <!-- 优惠券列表 --> <van-popup v-model:show="showList" round position="bottom" style="height: 90%; padding-top: 4px;" > <van-coupon-list :coupons="coupons" :chosen-coupon="chosenCoupon" :disabled-coupons="disabledCoupons" @change="onChange" @exchange="onExchange" /> </van-popup>
import { ref } from 'vue'; export default { setup() { const coupon = { available: 1, condition: '无门槛\n最多优惠12元', reason: '', value: 150, name: '优惠券名称', startAt: 1489104000, endAt: 1514592000, valueDesc: '1.5', unitDesc: '元', }; const coupons = ref([coupon]); const showList = ref(false); const chosenCoupon = ref(-1); const onChange = (index) => { showList.value = false; chosenCoupon.value = index; }; const onExchange = (code) => { coupons.value.push(coupon); }; return { coupons, showList, onChange, onExchange, chosenCoupon, disabledCoupons: [coupon], }; }, };

这段示例完整还原了真实业务链路:

  • coupons为可用优惠券数组,disabledCoupons为不可用优惠券数组,两者都传入CouponList,组件内部用 Tabs 分成“可使用优惠券”和“不可使用优惠券”两个 Tab 展示;
  • chosenCoupon初始为-1,表示未选中任何券;点击某张券时组件触发change事件并回传选中索引,我们在onChange中关闭弹层并同步chosenCoupon
  • 在兑换栏输入兑换码后点击“兑换”按钮,组件触发exchange事件并回传兑换码,业务方可在onExchange中调用真实兑换接口,成功后把新券 push 进coupons,列表即会实时刷新。

多选用法(chosenCoupon 传数组)

从源码看,chosenCoupon的类型是number | number[](见 CouponList.tsx)。当传入数组时,组件进入多选模式:点击优惠券时change事件回传的是新的选中索引数组,而非单个索引;同时点击底部按钮会回传[](清空全部选择),而不是-1。这一行为在updateChosenCoupon辅助函数中实现——若索引已在数组中则移除,否则追加(CouponList.tsx)。

多选模式的官方示例位于 demo/index.vue:将chosenCoupon绑定为ref<number[]>([]),通过#list-button插槽自定义一个“确定”按钮,点击后把选中的索引数组提交给结算页;同时设置:show-close-button="false"隐藏默认底部按钮,避免多选场景下出现语义不明确的“不使用优惠”按钮。

API

CouponCell Props

参数说明类型默认值
title单元格标题string优惠券
chosen-coupon当前选中优惠券的索引number | number[]-1
coupons可用优惠券列表Coupon[][]
editable能否切换优惠券booleantrue
border是否显示内边框booleantrue
currency货币符号string¥

CouponCell的展示逻辑值得留意:它会根据chosenCoupon汇总所有选中券的金额(叠加valuedenominations字段),在单元格右侧显示-¥ 15.00这样的汇总金额;当chosenCoupon-1且存在可选券时显示“N 张可用”,无券时显示“暂无可用券”。该格式化逻辑位于 CouponCell.tsx。editable控制isLink(右侧箭头),为false时单元格变为纯展示。

CouponList Props

参数说明类型默认值
v-model:code当前输入的兑换码string-
chosen-coupon当前选中优惠券的索引,支持多选(类型为[]number | number[]-1
coupons可用优惠券列表CouponInfo[][]
disabled-coupons不可用优惠券列表CouponInfo[][]
enabled-title可用优惠券列表标题string可使用优惠券
disabled-title不可用优惠券列表标题string不可使用优惠券
exchange-button-text兑换按钮文字string兑换
exchange-button-loading是否显示兑换按钮加载动画booleanfalse
exchange-button-disabled是否禁用兑换按钮booleanfalse
exchange-min-length兑换码最小长度number1
displayed-coupon-index滚动至特定优惠券位置number-
show-close-button是否显示列表底部按钮booleantrue
close-button-text列表底部按钮文字string不使用优惠
input-placeholder输入框文字提示string请输入优惠码
show-exchange-bar是否展示兑换栏booleantrue
currency货币符号string¥
empty-image列表为空时的占位图string-
show-count是否展示可用 / 不可用数量booleantrue

参数背后有几处值得展开的源码行为(均见 CouponList.tsx):

  • 兑换按钮的禁用判定buttonDisabled是一个computed,当exchangeButtonLoadingfalse且(exchangeButtonDisabled为真、兑换码为空、或兑换码长度小于exchangeMinLength)时,兑换按钮自动禁用(CouponList.tsx)。即只要在加载中,按钮永不因其它条件被禁用;
  • 兑换码的自动清空:点击兑换后触发exchange事件,若没有使用v-model:code绑定,则内部currentCode会被自动清空;若使用了v-model,则清空与否由外部数据决定(CouponList.tsx)。currentCode的任何变化都会同步触发update:code事件,配合v-model:code形成双向绑定(CouponList.tsx);
  • 滚动定位displayedCouponIndex变化时会通过nextTick后调用对应券项的scrollIntoView()自动滚动到指定优惠券(CouponList.tsx),onMounted时也会执行一次(CouponList.tsx);
  • 列表高度自适应updateListHeight会以「根容器高度(不足时回退为windowHeight)减去兑换栏与 Tab 头高度」来计算列表可视高度(Tab 头固定按 44px 计),并监听窗口高度变化实时重算,保证内部滚动区域精确贴合弹层(CouponList.tsx);
  • 数量角标showCounttrue时,Tab 标题会追加(N)形式的可用/不可用数量。

CouponList Events

事件名说明回调参数
change优惠券切换回调index, 选中优惠券的索引
exchange兑换优惠券回调code, 兑换码

事件语义与源码一一对应:点击某张可用券触发change(多选模式回传数组);点击底部“不使用优惠”按钮触发change(单选回传-1,多选回传[]);点击兑换按钮触发exchange。官方测试用例 index.spec.ts 验证了:兑换码为空时点击兑换不会触发exchange,输入有效兑换码后才触发;输入内容还会依次触发update:code事件,未绑定v-model:code时兑换后兑换码会被清空。

CouponList Slots

名称说明
list-footer优惠券列表底部
disabled-list-footer不可用优惠券列表底部
list-button自定义底部按钮

其中list-footer/disabled-list-footer分别渲染在两个 Tab 的列表末尾(CouponList.tsx 与 CouponList.tsx);list-button用于完全替换底部“不使用优惠”按钮,多选模式下的“确定”按钮正是通过该插槽实现的(CouponList.tsx)。

CouponInfo 数据结构

优惠券列表的每一项是一个CouponInfo对象:

键名说明类型
id优惠券 idstring
name优惠券名称string
condition满减条件string
startAt卡有效开始时间 (时间戳, 单位秒)number
endAt卡失效日期 (时间戳, 单位秒)number
description描述信息,优惠券可用时展示string
reason不可用原因,优惠券不可用时展示string
value折扣券优惠金额,单位分number
valueDesc折扣券优惠金额文案string
unitDesc单位文案string

从源码的类型定义看(Coupon.tsx),CouponInfo还支持discount(折扣,如88表示 8.8 折)、denominations(面额,单位分)、originCondition(原始满减门槛)等字段。券面的展示优先级为:

  1. 优先使用valueDesc + unitDesc组合文案(如1.5+8.8+);
  2. 否则若有denominations,显示货币符号 + 格式化面额
  3. 否则若有discount,显示X.X折
  4. 以上都没有则显示为空。

金额与折扣的格式化逻辑(去除无意义小数位)位于 coupon/utils.ts:formatAmount按「整数不保留小数、整十保留 1 位、其余保留 2 位」处理,formatDiscount仅在非整数折扣时保留 1 位小数。有效期文案由startAtendAt(秒级时间戳)格式化为年.月.日 - 年.月.日(coupon/utils.ts)。此外,当优惠券处于不可用状态(被放入disabledCoupons)时,组件展示reason(不可用原因)而非description,且不再显示勾选复选框(Coupon.tsx)。

类型定义

组件导出以下类型定义:

import type { CouponCellProps, CouponListProps, CouponInfo } from 'vant';

CouponListProps由 couponListProps 通过ExtractPropTypes推导而来,CouponCellProps同理;CouponListThemeVarsCouponCellThemeVars则分别定义在 types.ts 与 coupon-cell/types.ts,供 CSS 变量类型提示使用。

主题定制

样式变量

组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 ConfigProvider 组件。

名称默认值描述
--van-coupon-margin0 var(--van-padding-sm) var(--van-padding-sm)-
--van-coupon-content-height84px-
--van-coupon-content-padding14px 0-
--van-coupon-content-text-colorvar(--van-text-color)-
--van-coupon-backgroundvar(--van-background-2)-
--van-coupon-active-backgroundvar(--van-active-color)-
--van-coupon-radiusvar(--van-radius-lg)-
--van-coupon-shadow0 0 4px rgba(0, 0, 0, 0.1)-
--van-coupon-head-width96px-
--van-coupon-amount-colorvar(--van-danger-color)-
--van-coupon-amount-font-size30px-
--van-coupon-currency-font-size40%-
--van-coupon-name-font-sizevar(--van-font-size-md)-
--van-coupon-disabled-text-colorvar(--van-text-color-2)-
--van-coupon-description-paddingvar(--van-padding-xs) var(--van-padding-md)-
--van-coupon-description-border-colorvar(--van-border-color)-
--van-coupon-checkbox-colorvar(--van-danger-color)-
--van-coupon-list-backgroundvar(--van-background)-
--van-coupon-list-field-padding5px 0 5px var(--van-padding-md)-
--van-coupon-list-exchange-button-height32px-
--van-coupon-list-close-button-height40px-
--van-coupon-list-empty-tip-colorvar(--van-text-color-2)-
--van-coupon-list-empty-tip-font-sizevar(--van-font-size-md)-
--van-coupon-list-empty-tip-line-heightvar(--van-line-height-md)-
--van-coupon-cell-selected-text-colorvar(--van-text-color)-

其中--van-coupon-*系列变量作用于单个优惠券卡片(面额区、条件区、有效期、描述等),定义于 coupon/index.less;--van-coupon-list-*系列变量作用于整个选择器(背景、兑换栏、底部按钮、空态提示),声明于 coupon-list/index.less;--van-coupon-cell-selected-text-color则作用于单元格选中态文字颜色。所有变量的默认值均复用 Vant 的基础设计令牌(如--van-danger-color--van-background等),因此通过全局或局部(ConfigProvider)覆盖这些令牌即可实现整套换肤。

源码级原理小结

从整体实现看,CouponList的架构可概括为三个层次:

  1. 顶部兑换栏(exchange-bar):由Field(兑换码输入框,最长 20 字符)+Button(兑换按钮)组成,负责v-model:code的双向绑定与exchange事件抛出(CouponList.tsx);
  2. 中部 Tabs 双列表:基于Tabs/Tab实现“可使用优惠券”与“不可使用优惠券”两个页签,列表高度按弹层动态计算并支持内部滚动,空列表时渲染Empty占位(可自定义emptyImage)(CouponList.tsx);
  3. 底部操作区:默认渲染“不使用优惠”按钮,支持list-button插槽完全替换(CouponList.tsx)。

单张券的渲染由Coupon组件承担,它负责券面金额、满减条件、有效期、描述/不可用原因与选中态复选框的展示;测试用例 index.spec.ts 覆盖了快照渲染、空列表、自定义空图、兑换事件与插槽渲染等关键行为,可作为你二次开发时的回归参考。

结语

CouponCell+CouponList是 Vant 提供的开箱即用的优惠券选择完整方案:单元格负责汇总展示,列表负责选择、兑换与禁用券浏览,CouponInfo数据结构天然兼容“满减券、折扣券、面额券”三类常见形态。接入时只需维护couponsdisabledCouponschosenCoupon三个状态并响应change/exchange两个事件,再结合ConfigProvider与样式变量即可快速融入业务设计体系。

【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询