应统一用“分”为单位做整数运算:价格乘100转整数,数量保持整数,累加后除100并toFixed(2);子组件须通过update:modelValue通知父组件更新,禁止自行维护num副本。

uni-app购物车数量计算为什么总不准
直接用 item.num * item.price 累加再 toFixed(2),看似没问题,实际在 H5 和小程序上都可能因浮点误差导致总价差 0.01 元。这不是显示问题,是计算过程本身出错。
根本原因是 JS 浮点数无法精确表示十进制小数,比如 99.99 * 3 可能算出 299.97000000000003。小程序平台(尤其是微信、支付宝)对 Number 类型的处理更敏感,toFixed 只是截断,不是修正。
- 把价格单位统一转为“分”:所有
price读取时乘以 100,num保持整数,累加用reduce做整数运算 - 总价最终表达式必须是
(totalCent / 100).toFixed(2),不能写成totalCent.toFixed(2) - 避免在
map或forEach中用闭包变量累加,容易漏掉未选中项或重复计算 - 如果用了
vuex或pinia,总价逻辑必须放在getters或computed,别塞进methods里反复调用
父子组件传值时数量改了但父级不更新
常见于用 uniNumberBox 或自定义加减按钮封装在子组件里,父组件监听不到变化——本质是子组件没正确触发响应式通知。
uni-app 小程序端不支持 Vue 3 的 v-model:title 这类多参数绑定,也**不推荐直接解构 defineProps**。哪怕你写了 const { num } = defineProps(['num']),这个 num 就是只读快照,改它不会触发父组件更新。
- 子组件必须显式声明
props(Vue 2 写value+$emit('input');Vue 3 写modelValue+$emit('update:modelValue')) - 父组件绑定要严格对应:
<goodsitem :model-value="item.num"> item.num = val" /></goodsitem> - 不要在子组件里用
this.$parent或uni.$emit绕过 props —— 这会导致数据流不可追踪,调试时完全找不到源头 - 如果子组件需要校验(比如最小值为 1),应在触发
update:modelValue前完成判断,而不是等父组件再回调校验
全选/反选后子组件数量状态不同步
用户点了“全选”,商品数量框没重置为默认值(比如都变成 1),或者点了“删除选中”,某些子组件的 num 还卡在旧值——这说明父子间数量状态没形成闭环。
关键不在“谁改谁”,而在“谁拥有唯一数据源”。数量字段 num 必须是父组件 data 或 store 里的响应式字段,子组件只是渲染+反馈,不能自己维护一份副本。
- 子组件接收
num用props,修改时只发update:modelValue,绝不自行data: { localNum: 1 } - 父组件做全选操作时,要遍历列表并显式赋值:
this.list.forEach(item => item.num = 1),不能只改 UI 状态 - 如果用了
checkbox-group控制是否参与计算,记得数量变更逻辑要和勾选状态解耦——勾选状态影响是否计入总价,但数量变更应始终生效(比如用户想先调好数量再决定买不买) - 长列表场景下,确保每个
key是稳定唯一的(如:key="item.id + '-' + item.num"),否则 Vue 可能复用旧组件实例,导致num显示残留
uni-app跨端时数量计算结果不一致
H5 上总价是对的,微信小程序里少 0.01,支付宝小程序又多 0.01——这不是 bug,是各端 JS 引擎对 Number.prototype.toFixed 的实现差异,以及部分平台对浮点字面量解析精度不同。
最稳妥的方案是彻底规避浮点中间态。只要涉及金额,一律按“分”处理,且从接口返回那一刻起就转整数。
- 后端返回价格字段(如
price: 99.99)时,前端立刻存为priceCent: 9999,后续所有运算只用整数 - 子组件接收数量时,也只接收
num(整数),不接收任何带小数的“数量”,避免引入新浮点源 - 使用
uni.getSystemInfoSync().platform区分平台做兼容处理意义不大——浮点误差是语言层问题,不是平台 API 问题 - 测试阶段必须在真机上验证:模拟器的 JS 引擎和真机不同,H5 浏览器表现也不能代表小程序
真正难的不是写对一次计算,而是让所有组件在任意生命周期、任意操作顺序下,都维持数量与总价的一致性。很多问题爆发在“先改数量再取消勾选”或“快速连点加号”这种边界操作里,这时候靠 watch 深度监听比靠事件回调更可靠。


















