是的,Vue中的watch监听器在开发过程中经常用到,它可以监听指定的数据对象的变化,并在变化时触发相应的回调函数进行处理。但是由于Vue是响应式框架,watch监听器的触发时机会受到一些意外的影响,从而导致一些坑。本文将结合示例说明Vue中watch监听器的使用和坑及解决办法。
监听对象
Vue中可以使用$watch方法监听对象的属性变化,例如下面这个示例:
<template>
<div>
<p>age: {{age}}</p>
<button @click="changeAge">changeAge</button>
</div>
</template>
<script>
export default {
data() {
return {
age: 18,
}
},
methods: {
changeAge() {
this.age = 20
}
},
watch: {
age(newVal, oldVal) {
console.log(`age changed from ${oldVal} to ${newVal}`)
}
}
}
</script>
在上述代码中,我们定义了一个data对象,其中包含一个age属性。然后通过按钮click事件触发了changeAge方法,将age的值修改为20。同时,使用watch监听age的变化,并在值变化时触发相应的回调打印日志。
watch监听器触发时机
虽然watch监听器可以监听到对象的变化,但它的触发时机需要特别注意。需要注意的是,watch监听器的触发时机不仅受到对象自身的变化,还受到对象的引用变化的影响。
例如下面这个示例:
<template>
<div>
<p>age: {{age}}</p>
<p>person.age: {{person.age}}</p>
<button @click="changeObj">changeObj</button>
</div>
</template>
<script>
export default {
data() {
return {
age: 18,
person: {
age: 20,
}
}
},
methods: {
changeObj() {
this.person = { age: 22 }
}
},
watch: {
age(newVal, oldVal) {
console.log(`age changed from ${oldVal} to ${newVal}`)
},
'person.age'(newVal, oldVal) {
console.log(`person.age changed from ${oldVal} to ${newVal}`)
},
person: {
handler(newVal, oldVal) {
console.log(`person changed from ${JSON.stringify(oldVal)} to ${JSON.stringify(newVal)}`)
},
deep: true
}
}
}
</script>
在这个示例中,我们监听了age、person.age以及person三个变量的变化。并且使用changeObj方法将person重新赋值为{ age: 22 }。
需要注意的是,在Vue中,对象的引用变化也会触发watch监听器。因此,虽然person.age值未变化,但当person的引用变化时,它自身的watch监听器会触发。 同时,我们还使用了深度监听,因此可以观察到,当person的引用变化后,由于其内部属性age的值变化,因此也会触发深度监听器。最终控制台会输出这个结果:
person changed from {"age":20} to {"age":22}
person.age changed from 20 to 22
watch坑及解决办法
众所周知,Vue中对象的响应式变化是通过监听getter/setter实现的,因此watch的监听器是在setter后同步触发的。但是由于JavaScript的异步执行模型,有些情况下watch监听器的变化会发生在Vue内部的setter之前,从而会引起一些坑。
以DOM操作为例,当我们更新完数据之后,会进行DOM渲染操作。如果在DOM渲染完成之后再去修改数据,Vue的setter是没有问题的。但是如果在DOM渲染之前就去修改了数据,则setter是无法进行DOM更新的。此时如果使用watch监听属性变化,并在回调函数中进行DOM操作显然是错误的。
那么如何解决这个问题呢?Vue提供了一个Vue.nextTick()方法,它会在下一个DOM更新周期之后执行回调函数,从而保证了回调函数的执行时机。 因此,在需要在DOM更新后进行操作的情况下,我们可以利用这个方法。
例如下面这个示例:
<template>
<div>
<p>age: {{age}}</p>
<button @click="changeAge">changeAge</button>
</div>
</template>
<script>
export default {
data() {
return {
age: 18,
}
},
methods: {
changeAge() {
this.age = 20
this.$nextTick(() => {
console.log('DOM updated')
this.$refs.paragraph.textContent = this.age
})
}
},
watch: {
age(newVal, oldVal) {
console.log(`age changed from ${oldVal} to ${newVal}`)
}
}
}
</script>
在这个示例中,我们在changeAge方法中使用Vue.nextTick()方法,并在回调函数中进行DOM操作。即:改变了age的值后的下一次DOM更新周期,修改对应的p元素的textContent,保证了DOM更新和数据变化的同步性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue中watch监听器的触发时机(watch的坑及解决) - Python技术站