uni-progress不能直接做步进器,因其仅为线性进度条,缺乏点击跳转、状态回退、异步校验等核心能力,且无加减按钮、输入框及事件响应机制;手写stepper需处理数值边界控制、输入框防篡改、长按加速三关键逻辑。

uni-app里为什么不能直接用uni-progress做步进器
因为uni-progress是线性进度条,只反映百分比完成度,不支持“点击跳转”“状态回退”“异步校验”这些步进器核心能力。它没有加减按钮、输入框、禁用逻辑,也不能响应plus/minus事件——强行套用会导致交互断裂,比如用户点+1后库存不足,你没法拦截并提示。
手写Stepper必须处理的三个关键逻辑
纯CSS+Vue模板能跑通基础增减,但真实业务中这三件事漏一个就翻车:
- 数值边界控制:不是只靠
min/max属性,要结合async-change开关,在plus事件里调接口查库存,失败时手动还原v-model绑定值 - 输入框防篡改:设
disabled-input为true,同时监听blur事件做二次校验,避免用户粘贴非法字符或绕过按钮直接输值 - 长按加速:安卓/iOS对
touchstart和touchend的触发时机不一致,建议用setTimeout+clearTimeout实现节流,间隔设为150ms,比单纯@click更符合用户预期
u-number-box的坑:样式错位和父子传值失效
很多人用u-number-box发现数字居中偏移、加减按钮被裁切,根本原因是它的默认display: inline-flex在某些小程序平台(尤其是微信小程序基础库2.25.2以下)会忽略align-items: center。解决方案:
- 外层包一层
view并设display: flex; align-items: center - 给
u-number-box加style="width: 100%",否则H5端宽度不定 - 父子组件传值时,不要直接
v-model绑定props,改用:value+@change显式同步,否则子组件修改会触发Vue警告且值不同步
自定义Stepper组件的最小可行结构
不需要引入第三方库,一个.vue文件就能覆盖90%场景。关键代码骨架如下:
<template><view class="stepper"><view class="btn minus">−</view><input type="number" :value="innerValue" disabled><view class="btn plus">+</view></view></template><script>
export default {
props: {
value: { type: [Number, String], default: 0 },
min: { type: Number, default: 0 },
max: { type: Number, default: Infinity }
},
data() {
return { innerValue: this.value, timer: null, editable: true }
},
methods: {
onPlusStart() {
this.timer = setTimeout(() => {
this.doStep(1)
}, 300)
},
doStep(step) {
const next = Number(this.innerValue) + step
if (next < this.min || next > this.max) return
this.innerValue = next
this.$emit('change', next)
}
}
}
</script>
注意input标签必须用:value而非v-model,否则在iOS真机上会失去焦点后自动恢复旧值——这是Webview渲染层的老bug,绕不开。










