Vue踩坑之路之Vue Watch方法不能监听到数组或对象值的改变
面试官问过我一个问题:你知不知道Vue不能监听到数组或者对象属性值的变化,有什么解决办法?其实后来查出原理我都懂,还是挂在自己理解不深刻,脑海里没有一套完整的知识体系吧。如果当时面试官把问题分成两个来问我一:Vue的双向绑定原理答:利用数据劫持和发布者-订阅者模式监听数据值的变化,并且利用Object.defineproperty来重新定义对象的Get和Set方法。二:那Vue...
Vue不能监听到数组和对象值的变化其实和双向绑定的原理有关。Vue双向绑定原理是利用js中的Object.defineproperty重定义对象的GET和SET方法,而同时这种方法存在着缺陷。就是只能监听到对象内已有的值。在监听对象中属性变化的方法中中,无疑是使用ES6的proxy更为优越。
同时我对Vue中不能监听到数组对象变化也做了试验。代码如下。
let vm = new Vue({
el: '#app',
data: {
message: 'wxs',
arr:[1,2,3],
obj:{
name:'wxs',
age:21
}
},
methods:{
change:function () {
this.message = 'vue'
this.arr[0]=100
this.obj.name='xxx'
}
},
watch:{
message:function (newValue,oldValue) {
console.log('message改变了')
},
arr:function (newValue,oldValue) {
console.log('arr改变了')
},
obj:function (newValue,oldValue) {
console.log('obj改变了')
}
},
template: `<div><div>{{message}}</div><div>{{arr[0]}}</div><div>{{obj.name}}</div><button @click="change()">改变!</button></div>`
})
很简单的代码,设置按钮改变message,arr,obj的值,同时对这三个值的变化设置监听事件,测试结果如下。
视图显示三个值都发生了改变,但是Vue只监听到了第一个值的改变。
官方文档给出如下解释
对此Vue提供了解决办法。
Vue不能监听到数组变化官方文档中提出有以下有两种情况。
一:利用索引直接改变arr的值 如我在button事件中写的(arr[0]=1000)
解决方法 将this.arr[0]=1000改写为Vue可以监听的形式 this.$set(this.arr,0,1000)
this.$set接受三个参数,第一个是需要操作的数组对象,第二个是需要修改的数据的数组下标,第三个是修改后的值。
上图看效果。
将修改arr值得方法修改如下
methods:{
change:function () {
this.message = 'vue'
this.$set(this.arr,0,100)
this.obj.name='xxx'
}
},
成功监听
二:直接修改数组的长度 如this.arr.length=3
来做个测试。我们用修改数组长度得方法删除数组中的值,看看watch能不能监听的到。
methods:{
change:function () {
this.message = 'vue'
this.arr.length=0
this.obj.name='xxx'
}
},
结果,监听不到。
解决方法使用js中数组方法arr.splice操作数组达到修改长度的目的。
看看效果
methods:{
change:function () {
this.message = 'vue'
this.arr.splice(0,1)
this.obj.name='xxx'
}
},
我们将数组的第一个值删除,此时数组的第二个值变成了arr[0],渲染到了页面中,watch监听成功。
Vue中无法监听对象属性的添加或者删除
解决方法:this.$set(obj,name,‘xxx’)对对象进行操作时,set接受三个参数,第一个为对象的名称,第二个为对象的key值,第三个为key对应的value值。
this.obj=Object.assign({},this.arr,{
age:21,
major:'soft'
})
这样操作之后,便可以成功监听到数组和对象的变化了
methods:{
change:function () {
this.message = 'vue'
this.$set(this.arr,1,100)
this.$set(this.obj,'major','Vue')
}
},
控制台输出如下
那么问题来了,我改变的是对象的新值‘major’的值,请注意看我上面代码中method方法中的设置obj的代码。
此时Vue只是监听到了我改变了对象的新值。经过我测试,我改变对象的旧值,比如name值。Vue依然监听不到对象的变化。此时Vue提出了深度监听的方法如下。
但是这种方法经过我测试不能监听到对象新值的变化。
所以总结如下
总结:如果操作对象是数组,改变数组的值用Vue的$set方法,改变数组的长度用数组的splice方法使数组变化变成可监听的。如果操作对象是对象。如果操作的属性是对象内已经有的值,使用$watch,加上关键字deep深度监听对象,如果操作的属性是对象内没有的新属性。使用$set使对象变成可监听的!
如果有不理解的或不正确的地方欢迎提出。
更多推荐
所有评论(0)