方法一,直接监听list.list2
watch:{
'list.list2': {
handler(newVal, oldVal) {
debugger;
},
deep: true,
immediate: false,
sync: true
}
}
deep是用来监听对象内部变化,监听数组变更不需要设置,但是如果数组内还是个对象就需要了
immediate 文档里说将立即以表达式的当前值触发回调,没看懂变化,如果是个基本对象好像在生命周期initState时会调用一次
sync是个不在文档里出现的选项,设置之后调用栈里就不会是promise.then,而是直接调用到handler位置,相当于监听提前于$nextTick进行. 我们项目代码用了很奇怪的方法,所以如果不加sync调用栈里找不到源码位置,加入后就可以在调用栈中查看修改这条数据时是哪句源码进行的, 测试代码看不到这个问题.
缺陷: newVal和oldVal永远相同,因为是个对象,所以内存地址相同
方法2
computed结合watch
{
computed:{
computedObjectToBeWatched() {
return JSON.stringify(this.list.list2);
}
},
watch:{
computedObjectToBeWatched: {
deep: true,
handler(newVal, oldVal) {
if (newVal !== oldVal) {
debugger;
}
}
}
}
}
由上面的方法1知道在handler时拦截的变量地址是相同的,那就先用computed将old设置为一个不相同的变量,比如直接转为JSON,这样在watch比较时就是两个字符串进行比较了,而且比较的方法比较粗暴是单纯的比较,也可以写的更精准,比如每个对象的数据进行比较.
写作原因
因为项目历史原因,代码比较复杂,各个地方可能都会直接修改data的数据,这时候可能就不知道触发的是哪条代码导致对象进行了修改,所以上网寻找一些调试方法,最原始的方法就是读代码直接看,而用vue的watch才是更简单的方法.
基本代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<template>
<div v-for="item in list.list2">
<span>{{item.show}} {{item.name}}</span>
</div>
<button @click="set">切换</button>
</template>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
list: {
list2: [
{ id: 0, show: true, name: '张三' },
{ id: 1, show: false, name: '李四' },
{ id: 2, show: true, name: '王五' }
]
}
},
methods:{
set: function(){
this.list.list2[0].show = !this.list.list2[0].show
}
},
computed:{
},
watch: {
}
})
</script>
点击切换按钮,list的list2的第一个show就会改变,我的项目有多层对象,就用多层对象做示例了
来源: Stack Overflow链接