一、事出场景
<template>
<div>
<el-button @click="handleChangeId">改变id</el-button>
<el-button @click="handleAdd">添加</el-button>
<ul>
<li v-for="item of params.list" :key="item">{{ item }}</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
params: {
id: '1',
list: [1, 2, 3, 4]
}
};
},
watch: {
params: {
handler (newVal, oldVal) {
console.log('监听params', newVal, oldVal);
const flag = JSON.stringify(newVal) === JSON.stringify(oldVal);
console.log(flag);
},
deep: true
}
},
methods: {
handleChangeId () {
this.params.id = '2';
},
handleAdd () {
const { length } = this.params.list;
this.params.list.push(length + 1);
},
}
};
</script>
例子就是上面这样一个结构,当点击【改变id】或【添加】按钮时,flag是true还是false?
这特么肯定是false啊,要是true就不会打印啊。。。
但其实打印的是true
二、为什么打印true?
原因是因为监听的params是一个对象,对象的引用指向同一个对象,所以新值和旧值是相同的。人家就是这么设计的
三、如何解决
应该说如何正确地使用watch去监听
'params.id': {
handler (newVal, oldVal) {
console.log('监听params.id', newVal, oldVal);
}
},
'params.list': {
handler (newVal, oldVal) {
console.log('监听params.list', newVal, oldVal);
},
deep: true
}
以上,id是可以正常监听到变化的,因为它是简单数据类型。但是list还是新值和旧值一样呢,因为list是引用数据类型,它的引用指向同一个数组。。和params的原因一样
那我们可以通过computed切断list的引用关系:
computed: {
list () {
return JSON.parse(JSON.stringify(this.params.list));
}
},
watch: {
list: {
handler (newVal, oldVal) {
console.log('监听list', newVal, oldVal);
},
deep: true
}
}
这样,你才可以知道真正的旧值是啥样。
那一开始的params的监听实际应该写成这样:
computed: {
newParams () {
return JSON.parse(JSON.stringify(this.params));
}
},
watch: {
newParams: {
handler (newVal, oldVal) {
console.log('监听newParams', newVal, oldVal);
},
deep: true
}
},