Vant Weapp Stepper 步进器组件完全指南:从基础用法到源码级原理剖析

Vant Weapp Stepper 步进器组件完全指南:从基础用法到源码级原理剖析

【免费下载链接】vant-weapp 轻量、可靠的小程序 UI 组件库 【免费下载链接】vant-weapp 项目地址: https://gitcode.com/gh_mirrors/va/vant-weapp

Stepper 步进器是 Vant Weapp(轻量、可靠的小程序 UI 组件库)中用于在指定范围内输入、调整数字的核心组件,由增加按钮、减少按钮和输入框三部分组成。本文基于 packages/stepper/README.md 完整梳理其引入方式、全部属性与事件 API,并深入 packages/stepper/index.ts 源码,剖析数值格式化、范围钳制、长按连续触发等底层实现原理,帮助你从"会用"进阶到"懂原理",在实际小程序项目中灵活应对步进器的各种定制需求。

组件介绍与引入

步进器由增加按钮、减少按钮和输入框组成,用于在一定范围内输入、调整数字。它是电商购物车数量、表单数字项等场景中的高频组件。

在 app.json 或对应页面的 index.json 中声明组件(完整引入方式可参考 快速上手):

"usingComponents": {
  "van-stepper": "@vant/weapp/stepper/index"
}

组件本质上是微信小程序自定义组件,其 index.json 仅声明 "component": true(见 packages/stepper/index.json)。组件实现通过 VantComponent 工厂封装,该工厂在 packages/common/component.ts 中将 props、watch、methods 等配置映射为微信原生 Component 的 properties、observers、methods,并自动注入 wx://form-field 表单行为——这意味着步进器可以直接参与表单提交,这正是 name 属性存在的意义。

代码演示:九种核心用法

以下用法与官方 Demo(packages/stepper/demo/index.wxml)一一对应,均可直接复制运行。

基础用法

通过 value 设置输入值,通过 change 事件监听输入值变化:

<van-stepper value="{{ 1 }}" bind:change="onChange" />
Page({
  onChange(event) {
    console.log(event.detail);
  },
});

change 事件的回调参数 event.detail 为当前输入值(数字类型),具体见下文事件表。

步长设置

通过 step 属性设置每次点击增加或减少按钮时变化的值,默认为 1:

<van-stepper value="{{ 1 }}" step="2" />

源码中步长参与加减运算的位置在 packages/stepper/index.ts 的 onChange 方法:const diff = type === 'minus' ? -this.data.step : +this.data.step;。

限制输入范围

通过 min 和 max 属性限制输入值的范围:

<van-stepper value="{{ 5 }}" min="5" max="8" />

注意:min、max、step 等属性的类型均为 string | number,传字符串(如 "5")与传数字(如 5)效果一致,源码内部统一通过 + 一元运算符转为数字比较。min 默认值为 1,max 默认值为 Number.MAX_SAFE_INTEGER(见 packages/stepper/index.ts 中 props 定义),即默认不设上限。

限制输入整数

设置 integer 属性后,输入框将限制只能输入整数:

<van-stepper value="{{ 1 }}" integer />

integer 属性在 filter 方法中生效:当输入值包含小数点时,直接截取小数点前的整数部分(value.split('.')[0])。同时,WXML 中输入框的 type 会根据 integer 在 number(整数键盘)与 digit(带小数点键盘)之间切换(见 packages/stepper/index.wxml)。

禁用状态

通过设置 disabled 属性来禁用步进器,禁用状态下无法点击按钮或修改输入框:

<van-stepper value="{{ 1 }}" disabled />

disabled 会同时作用于按钮(WXML 中 van-stepper__minus / van-stepper__plus 增加 disabled 修饰类)和输入框(disabled 与 disableInput 会同步传递给 <input>)。

关闭长按

通过设置 long-press 属性决定步进器是否开启长按手势,默认开启:

<van-stepper value="{{ 1 }}" long-press="{{ false }}" />

注意 long-press 的默认值为 true,若要关闭必须显式传入 false。

固定小数位数

通过设置 decimal-length 属性可以保留固定的小数位数:

<van-stepper value="{{ 1 }}" step="0.2" decimal-length="{{ 1 }}" />

decimal-length 不传时按实际值显示;传入后内部使用 toFixed(decimalLength) 强制格式化输出。

异步变更

如果需要异步地修改输入框的值,可以设置 async-change 属性,并在 change 事件中手动修改 value:

<van-stepper value="{{ value }}" async-change bind:change="onChange" />
Page({
  data: {
    value: 1,
  },

  onChange(event) {
    Toast.loading({ forbidClick: true });

    setTimeout(() => {
      Toast.clear();
      this.setData({ value: event.detail });
    }, 500);
  },
});

该场景典型应用于"需要向服务端校验或提交后再更新本地值"的业务,官方 Demo 的完整实现见 packages/stepper/demo/index.ts。异步模式的底层逻辑在 emitChange 中:当 asyncChange 为 true 时,组件不会主动 setData 更新 currentValue,仅向外抛出 change 事件,由业务方决定何时把新值写回 value。

自定义大小

通过 input-width 属性设置输入框宽度,通过 button-size 属性设置按钮大小和输入框高度:

<van-stepper value="{{ 1 }}" input-width="40px" button-size="32px" />

input-width 默认值为 32px,button-size 默认值为 28px,二者默认单位为 px。尺寸最终由 packages/stepper/index.wxs 中的 buttonStyle / inputStyle 计算:按钮宽高均为 buttonSize,输入框宽度为 inputWidth、高度与按钮一致,保证三者视觉对齐。

圆角风格(Demo 补充)

除了 README 列出的用法,官方 Demo 还展示了 theme="round" 圆角风格:

<van-stepper value="{{ 1 }}" theme="round" button-size="22px" />

该样式在 packages/stepper/index.less 的 &--round 中实现:按钮变为圆形、加号按钮使用主题色填充、减号按钮为白底描边,圆角风格下输入框背景透明。

API 详解

Props 属性表

参数说明类型默认值
name在表单内提交时的标识符string-
value输入值string | number最小值
min最小值string | number1
max最大值string | number-(源码中为 Number.MAX_SAFE_INTEGER)
step步长string | number1
integer是否只允许输入整数booleanfalse
disabled是否禁用booleanfalse
disable-input是否禁用输入框booleanfalse
async-change是否开启异步变更,开启后需要手动控制输入值booleanfalse
input-width输入框宽度,默认单位为 pxstring | number32px
button-size按钮大小,默认单位为 px,输入框高度会和按钮大小保持一致string | number28px
show-plus是否显示增加按钮booleantrue
show-minus是否显示减少按钮booleantrue
decimal-length固定显示的小数位数number-
theme样式风格,可选值为 roundstring-
disable-plus是否禁用增加按钮boolean-
disable-minus是否禁用减少按钮boolean-
long-press是否开启长按手势booleantrue
always-embed(v1.9.3 起)强制 input 处于同层状态,默认 focus 时 input 会切到非同层状态(仅在 iOS 下生效)booleanfalse

几个容易被忽略的细节:

  • show-plus / show-minus 控制按钮显隐:在 packages/stepper/index.wxml 中分别以 wx:if="{{ showMinus }}" 与 wx:if="{{ showPlus }}" 实现,可组合出"只增不减"或"只减不增"的形态。
  • disable-plus / disable-minus 与 disabled 相互独立,仅禁用单个方向按钮。结合 isDisabled 方法可看出,按钮禁用逻辑为:disabled || disablePlus || +currentValue >= +max(加号)、disabled || disableMinus || +currentValue <= +min(减号),即达到边界值时按钮自动进入禁用态,此时点击会触发 overlimit 事件而非 change。
  • always-embed 用于解决 iOS 上输入框 focus 时从同层切换到非同层引起的布局抖动问题,仅在 iOS 生效。

Events 事件表

事件名说明回调参数
bind:change当绑定值变化时触发的事件event.detail: 当前输入的值(数字类型)
bind:overlimit点击不可用的按钮时触发-(源码中携带 type:'plus' 或 'minus')
bind:plus点击增加按钮时触发-
bind:minus点击减少按钮时触发-
bind:focus输入框聚焦时触发-(透传 input 的 event.detail)
bind:blur输入框失焦时触发-(源码中携带 value: +data.newValue)

Slot 插槽

名称说明
plus加号按钮
minus减号按钮

按钮内部均预留了 <slot>(见 packages/stepper/index.wxml),可通过自定义插槽内容完全替换默认的 + / - 图形,例如放置自定义图标。插槽为空的按钮会通过 CSS 伪元素 ::before / ::after 绘制默认加号、减号线条(见 packages/stepper/index.less)。

外部样式类

类名说明
custom-class根节点样式类
input-class输入框样式类
plus-class加号按钮样式类
minus-class减号按钮样式类

外部样式类在源码中通过 classes: ['input-class', 'plus-class', 'minus-class'] 声明,custom-class 则由 VantComponent 工厂自动追加(见 packages/common/component.ts),它们会渲染到 WXML 对应节点的 class 上,供页面侧覆盖样式。

源码级原理剖析

数值处理的完整流水线:filter → format → emitChange

步进器所有数值操作都经过 filter、format 两道关卡,最终由 emitChange 输出(packages/stepper/index.ts):

  1. filter(过滤非法字符):先用正则 /[^0-9.-]/g 剔除所有非数字、小数点、负号的字符;若开启了 integer 且值包含小数点,则截断为整数部分。
  2. format(格式化):先对 safeValue 做范围钳制 Math.max(Math.min(max, +safeValue), min),将值强制限制在 [min, max] 区间内;随后若配置了 decimal-length,用 toFixed(decimalLength) 补齐小数位。
  3. emitChange(变更分发):非异步模式下将格式化后的值写回 currentValue 并抛出 change 事件;异步模式下只抛事件、不写值。

值得注意的边界处理:

  • 允许输入框临时为空:onInput 中 value === '' 时直接 return,避免用户清空输入框时被强制回填,保证删除操作的流畅性。
  • 小数输入体验修复:emitChange 中有一段注释为 fix when input 11. parsed to 11, unable to enter decimal,即当用户输入 11. 时,若直接使用格式化后的值会丢失小数点导致无法继续输入小数位,因此源码采用 +value === +newValue ? value : newValue 的策略:数值相等时保留用户原始输入字符串(含尾随小数点),否则采用规范化结果。
  • 浮点精度处理:add 函数通过放大 10^10 倍取整后再缩小,规避 0.1 + 0.2 这类经典浮点误差,这也是 step="0.2" 组合场景能稳定工作的原因。

按钮点击与边界:isDisabled 与 overlimit

按钮点击统一走 onTap(读取 data-type 区分 plus / minus)。onChange 首先调用 isDisabled 判断:若因 disabled、disablePlus / disableMinus 或到达 max / min 边界而禁用,则触发 overlimit 事件并提前返回;否则按方向计算 diff(加号取 +step,减号取 -step),经 format 钳制边界后走 emitChange,最后再抛出 plus / minus 事件。WXML 中按钮的禁用态样式(van-stepper__plus--disabled 等)与 isDisabled 的判定条件保持一致。

长按手势的实现机制

long-press 的默认开启意味着组件内部有一套独立的触摸计时逻辑,核心常量在源码顶部定义:

  • LONG_PRESS_START_TIME = 600:触摸按下后持续 600ms 判定为长按;
  • LONG_PRESS_INTERVAL = 200:长按生效后每 200ms 自动触发一次步进。

具体流程(见 packages/stepper/index.ts 的 onTouchStart / longPressStep / onTouchEnd):触摸开始时若 longPress 开启则启动 600ms 定时器;600ms 内松手则清空定时器、仅执行单击;超过 600ms 判定为长按,立即触发一次 onChange 并通过 longPressStep 递归注册 200ms 定时器实现连续步进,直到 onTouchEnd 清除定时器。若 long-press 为 false,onTouchStart / onTouchEnd 直接返回,仅保留单击行为。

输入框的受控刷新:watch 与 check

组件通过 watch.value 监听外部 value 变化,调用 observeValue 将格式化后的值同步到内部 currentValue(输入框实际绑定的是 currentValue)。integer、decimalLength、min、max 四个属性均注册了 check 观察者:属性变化时立即用 format 重新校验并修正 currentValue,并用 equal(字符串比较)避免无意义的重复 setData。这种"外部受控 + 内部兜底"的设计,保证了组件在动态修改属性时输入框始终处于合法状态。

测试验证

组件 Demo 通过快照测试保障渲染稳定性:packages/stepper/test/demo.spec.ts 使用 miniprogram-simulate 加载 demo/index 并断言渲染结果与快照一致(快照见 packages/stepper/test/snapshots/demo.spec.ts.snap)。如果你在修改组件或定制样式后需要回归验证,可参考该测试的写法在仓库中运行对应测试用例。

样式定制

步进器的尺寸与颜色大量使用 CSS 变量(见 packages/stepper/index.less),可以在页面级覆盖,例如:

  • --stepper-background-color:按钮与输入框背景色
  • --stepper-input-width / --stepper-input-height:输入框宽高
  • --stepper-input-font-size / --stepper-input-text-color:输入框字号与文字颜色
  • --stepper-button-icon-color:按钮图标颜色
  • --stepper-border-radius:按钮圆角
  • --stepper-active-color:按钮按压态背景色

加上前文介绍的外部样式类与插槽机制,步进器基本可以无侵入地适配各类业务视觉规范。

总结

Stepper 步进器虽然 API 简洁,但内部凝聚了输入过滤、范围钳制、小数精度、异步受控、长按计时等多重工程细节。掌握本文的属性与事件全表,即可覆盖"限范围、限整数、定步长、保小数、异步提交、自定义尺寸与风格"等绝大多数业务场景;理解其 filter → format → emitChange 流水线与长按机制后,更能举一反三,在遇到深层定制需求时快速定位源码(packages/stepper/index.ts、packages/stepper/index.wxml、packages/stepper/index.wxs)进行精准改造。

【免费下载链接】vant-weapp 轻量、可靠的小程序 UI 组件库 【免费下载链接】vant-weapp 项目地址: https://gitcode.com/gh_mirrors/va/vant-weapp

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

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值