今天碰到一个场景,在uniapp中,定义了一个input输入框,输入框被限制只能输入数字,
我用了v-model进行双向数据绑定(值为inputValue),并且在input事件中,对数据进行了处理,
最后将处理后的数据赋值给inputValue,经过日志打印会发现,inputValue的值已经改变了,
但是页面上展示的数据仍然没有改变
比如说,我先输入5,再输入a,此时页面展示还是5a但是我打印出来的数据已经是5了,
更神奇的是,当我再输入一个5时,此时页面视图改变,成55
代码片段
// html 部分
<input
v-model="inputValue"
@input="handleChange"
/>
// js部分
handleChange(e) {
let currentvalue = e.target.value; // 这是当前获取到的值
console.log('value', e.target.value);
let value = currentvalue.replace(/\D/g, ''); // 处理非数字的数据
this.inputValue = value;
console.log('this.inputValue', this.inputValue) // 这里输出的结果显示值已经变成了处理后的结果
}
先说解决方案
解决方案
在进行赋值操作时,在$nextTick或者setTimeout的回调中,进行赋值操作
handleChange(e) {
let currentvalue = e.target.value; // 这是当前获取到的值
console.log('value', e.target.value);
let value = currentvalue.replace(/\D/g, ''); // 处理非数字的数据
// 方法一
this.$nextTick(() => {
this.inputValue = value;
console.log('this.inputValue', this.inputValue) // 这里输出的结果显示值已经变成了处理后的结果
})
// 方法二
setTimeOut(() => {
this.inputValue = value;
console.log('this.inputValue', this.inputValue) // 这里输出的结果显示值已经变成了处理后的结果
},0)
}
分析
以下分析内容不一定正确,仅供参考
首先分析为什么原来的方法视图不会更新
- 首先我们要知道,vue的视图更新机制,也就是说当我们修改了数据的时候,他并不会立即去进行视图的更新,而是将更新操作放到下一个事件循环中,所以视图的更新是异步的。
- 当任务队列执行到更新操作时,会拿当前的数据和原始的数据进行对比,如果有修改,就去调用视图刷新的方法。
- 所以当我们v-model修改数据的时候,比如我原先是5,我再输入a的时候,vue会将一个更新任务放到任务队列中等待执行,但是因为我在input事件中,利用replace方法将5a变成5,同时将值又赋给了inputValue,所以当更新任务执行的时候,会发现,原始值5和现在的值都是5,并没有改变,所以不会触发视图更新的方法,所以页面上依旧保持着是5a,但是我们的值已经改变了
接着我们来分析原先的情况下,为什么在最后输入数字又会导致视图更新了
- 当我再输入一个5时,此时更新任务中,原始值为5,现在的值为55,所以会触发视图更新,解决了我们碰到的神奇的情况。
最后我们来分析为什么将赋值操作放在nextTick中会起作用
- 而当我们将赋值操作放到nextTick或者setTimeout中时,他们会在当前视图更新完成后执行里面的回调,所以在v-model改变数据为5a后,视图会先去更新一遍,此时值为5a。
- 然后在nextTick中,我们再去改变inputValue的值时,会再向任务队列里添加一个更新任务,此时取到的原始值就是5a,目前的值就是5,所以会触发视图的更新操作,于是完成了视图的更新
总结
- 视图的更新是异步的,在更新时会比较原先的值和现在的值是否相等,不相等的话进行视图更新
- 所以如果赋值操作是同步的话,就很容易造成两个值对比时相等的情况,从而造成视图不更新,解决方案就是进行异步赋值,即使用nextTick或者setTimeout。
其他方案
之前在网上还看到其他几种方案,我试了都没起作用,这里罗列出来,仅供参考
- 1、有的说是v-model绑定的层级太深了,比如说**v-model=”data.person.name”**这种,解决方法就是定义一个简单的变量如inputValue来接受他的值,再通过改变inputValue的值来改变视图
- 2、有的说是v-model的问题,可以通过自己实现双向绑定的方式来解决,比如:value=”inputValue”,然后在input事件中对value赋值
原文链接:https://juejin.cn/post/7234058802743427132 作者:奈何天丶