uniapp中uview组件中u-input格式化后赋值踩坑

背景是 uniapp打包的安卓app中 u-input输入超过5位小数以上需要保留5位小数

复制代码
  <u-input " type="text"" v-model="value[label.value]" @input="handleInput" @blur="handleBlur" />
javascript 复制代码
//写法1:不能保留5位小数
 handleInput(value) {
      const formattedValue = formatNumberDP(value, this.label.decimalPlaces)
      this.$set(this.value, this.label.value, formattedValue)
        this.$emit('valueChange', {
          label: this.label,
          value: formattedValue,
          all: this.value
        })
    },

//写法2:不能保留5位小数
 handleInput(value) {
      const formattedValue = formatNumberDP(value, this.label.decimalPlaces)
      this.$set(this.value, this.label.value, formattedValue)
      this.$nextTick(() => {
      
        this.$emit('valueChange', {
          label: this.label,
          value: formattedValue,
          all: this.value
        })
      })
    },

//写法3:正确保留5位小数
 handleInput(value) {
      const formattedValue = formatNumberDP(value, this.label.decimalPlaces)
      this.$nextTick(() => {
        this.$set(this.value, this.label.value, formattedValue)
        this.$emit('valueChange', {
          label: this.label,
          value: formattedValue,
          all: this.value
        })
      })
    },

问题来了: v-model本质就是双向绑定 数据同步更新试图 为啥不起作用了 还要用$nextTick??????

为什么不加this.$nextTick回调,直接失败?

这个问题的核心在于:v-model 的 "双向绑定" 并非 "同步实时绑定",它仍然受限于 Vue 的异步更新机制,且在复杂组件(如 u-input)中可能存在额外的内部处理逻辑,导致数据与视图的更新存在微小延迟

1. v-model 的双向绑定本质:"双向"≠"同步"

v-model 的双向绑定可以拆解为:

  • 视图→数据:用户输入时,触发 input 事件,同步更新绑定的数据(这一步是同步的)。
  • 数据→视图:数据变化时,Vue 会异步更新视图(这一步是异步的,受 Vue 更新队列控制)。

也就是说:

用户输入→数据更新(同步);

数据更新→视图渲染(异步,需要等待 Vue 的更新队列执行)。

这就是为什么即使有 v-model,修改数据后也不能立刻拿到更新后的 DOM------ 因为数据到视图的过程是异步的。

2. 为什么在 u-input 中需要 $nextTick?

u-input 作为封装后的组件,比原生 input 更复杂,它的内部逻辑可能会加剧这种 "异步延迟":

  • 组件内部的状态维护 :u-input 可能会自己维护一个内部值(比如innerValue),而非直接使用 v-model 绑定的值。当你通过this.$set修改外部数据时,组件需要通过watchprops监听来更新内部值,这个过程可能有延迟。
  • 输入行为的拦截与处理 :比如你输入小数点后,u-input 可能会先执行自己的校验、格式化(如限制长度),再同步到外部数据。如果你的代码在它完成内部处理前就修改数据,可能会被组件的内部逻辑覆盖(写法2就是被覆盖了)。

此时,$nextTick的作用就是等待:

  • 等待 u-input 完成内部状态同步(内部值→外部 v-model 数据);
  • 等待 Vue 完成数据到视图的异步更新(确保 DOM 已渲染最新值)。

只有这两个步骤都完成后,你的格式化操作才能稳定生效,不会被组件后续的处理冲掉。

3. 举例说明:为什么 v-model 在此时 "看似失效"?

假设用户输入了123.4(需要格式化为123.40000):

没有 $nextTick(写法 2):
  1. 用户输入123.4,触发 input 事件,v-model 同步将数据更新为123.4(视图→数据,同步)。
  2. 你的代码立即执行this.$set,将数据改为123.40000(试图格式化)。
  3. 但此时 u-input 可能还在处理内部逻辑 :比如它的内部innerValue还是123.4,并且计划在同步代码结束后,将innerValue同步到外部数据(覆盖你刚设置的123.40000)。
  4. 最终数据被组件内部逻辑覆盖回123.4,格式化失败。
有 $nextTick(写法 1):
  1. 用户输入123.4,v-model 同步将数据更新为123.4
  2. 你的代码进入$nextTick等待。
  3. 等待 u-input 完成内部处理:innerValue同步到外部数据(此时数据还是123.4,但组件内部状态已稳定)。
  4. 等待 Vue 完成 DOM 更新(视图显示123.4)。
  5. $nextTick回调执行,this.$set将数据改为123.40000,此时组件内部已无后续覆盖逻辑,数据和视图稳定更新为格式化后的值。

结论

v-model 的双向绑定确实能保证数据与视图的一致性,但这种一致性是异步达成的 (数据变化→Vue 更新队列→视图渲染)。在复杂组件(如 u-input)中,还可能存在组件内部的状态同步延迟,因此需要$nextTick来等待所有异步操作完成,确保你的格式化逻辑在 "正确的时机" 执行,避免被组件的内部处理覆盖。

没理解可以继续看:解释写法2和写法3:

由于u-input内部处理的复杂特性,写法2和写法3 问题出在 u-input 组件对数据更新的时机敏感性上

1. 写法 2 失效的关键原因

写法 2 是同步执行this.$set修改数据,此时:

  • u-input 可能还在处理用户输入的同步逻辑(比如还没完成原始值的记录),你的格式化值会被组件后续的默认处理覆盖。
  • 对于 u-input 这类封装组件,其v-model绑定可能存在 "双向绑定延迟"------ 同步修改数据后,组件的视图更新依赖于下一次事件循环,而在这之前,用户的输入行为可能已经触发了新的状态覆盖。

简单说:写法 2 的同步更新太早,被组件的原生输入处理逻辑 "覆盖" 了;写法 1 的延迟更新刚好卡在组件处理完原生输入后,因此能生效

3. 写法 3有效的核心逻辑

写法 3 的流程是:先计算格式化值 → 等待$nextTick → 再更新数据并触发事件。

这个过程刚好契合了 u-input 的内部处理机制:

  • 避开输入事件的同步阶段 :u-input 在接收用户输入时(比如输入小数点),会在同步代码中处理原生输入行为(如更新输入框显示、维护光标位置)。如果在这个阶段同步修改数据(写法 2 的this.$set),会与组件的原生处理产生冲突 ------ 组件可能会用原生输入的原始值覆盖你设置的格式化值。
  • 在组件内部状态稳定后更新$nextTick会等待 u-input 完成当前输入的所有同步处理(包括原生 DOM 更新、内部状态记录),此时再通过this.$set设置格式化值,相当于 "在组件处理完原始输入后再覆盖结果",不会被组件的内部逻辑冲掉,因此能稳定保留 5 位小数。
相关推荐
奕辰杰22 分钟前
关于npm前端项目编译时栈溢出 Maximum call stack size exceeded的处理方案
前端·npm·node.js
JiaLin_Denny2 小时前
如何在NPM上发布自己的React组件(包)
前端·react.js·npm·npm包·npm发布组件·npm发布包
_Kayo_2 小时前
VUE2 学习笔记14 nextTick、过渡与动画
javascript·笔记·学习
路光.3 小时前
触发事件,按钮loading状态,封装hooks
前端·typescript·vue3hooks
我爱996!3 小时前
SpringMVC——响应
java·服务器·前端
咔咔一顿操作4 小时前
Vue 3 入门教程7 - 状态管理工具 Pinia
前端·javascript·vue.js·vue3
kk爱闹4 小时前
用el-table实现的可编辑的动态表格组件
前端·vue.js
漂流瓶jz5 小时前
JavaScript语法树简介:AST/CST/词法/语法分析/ESTree/生成工具
前端·javascript·编译原理
换日线°5 小时前
css 不错的按钮动画
前端·css·微信小程序