侦听器 _watch:
作用:可以侦听data和computed中数据的变化.
语法
watch: { "被侦听的属性名" (newVal, oldVal){ } }
监听简单数据类型时可以直接使用,而监听复杂数据类型时,例如当我们只需要监听data或者computed中对象的某个属性时,可以使用字符串的形式进行监听.
//举例:
watch: {
//字符串形式 表示监听item对象下的good_count属性
'item.goods_count'(newval) {
if (newval <= 0) {
this.item.goods_count=1
}
}
}
在watch中,如果对对象进行监听,只有对象obj被重新赋值时
,watch才会被监听到,这个时候无法对obj里面的属性的变化进行监听,我们也可以给watch对象加上深度监听属性.
handler(newval, oldval) {
console.log("完整写法,监听复杂数据类型", newval);
},
deep: true, //表示开启深度监听
immediate: true, //立即监听,在页面初始化时,会监听一次
}
而监听复杂数据类型,当复杂数据类型被改变之后,newval的值改变,由于newval和oldval都指向同一个对象
,导致oldval也会随之改变,打印出来则没有了old和new之分.
解决方法:在初始化的时候,深克隆一个oldval.
也有看其他人写的文章解决方案,都大差不差,都是使用一个计算属性加上深拷贝,看别人的回答时总感觉很拗口.于是自己总结了一下.
在我看来,解决此问题的关键在于:我们此时遇到的问题就是新值与旧值指向同一个地址的问题.而深拷贝的特点就是新开辟一个地址储存需要拷贝对象的所有属性.然后指向这个新地址. 故 JSON.parse(JSON.stringify())
能完美解决其中的问题.然后与计算属性合并达到监听的属性一旦变化,自动新开辟一个地址,储存新值.而新值与旧值指向的地址不同,则解决了新值与旧值相同的问题.
<div id="app">
<input type="text" v-model="lzy.age" />
</div>
</template>
<script>
export default {
name: "App",
watch: {
lzy2: {
handler(newvalue, oldvalue) {
console.log("新值");
console.log(newvalue);
console.log("旧值");
console.log(oldvalue);
console.log(oldvalue===this.lzy);
},
deep: true,
},
},
data() {
return {
lzy: {
gender: "man",
age: 21,
},
};
},
computed: {
lzy2(){
return JSON.parse(JSON.stringify(this.lzy))
// 因为计算属性一开始就执行了一次,相当于在一开始就深拷贝拿到了oldvalue,改变之后又再一次深拷贝,每一次深拷贝生成的对象都是指向不同的地址,所以oldvalue和newvalue是两个不同的地址.
},
},
};
</script>
<style scoped>
</style>