当需要在数据变化时执行异步或开销较大的操作时,需要watch 选项提供了一个更通用的方法,来响应数据的变化。
watch的基础用法
通过对象监听对象内部属性的示例:
<template>
<div>
<p>{{ obj.a }}</p>
<input v-model="obj.a" />
<p>{{ obj.b }}</p>
<input v-model.number="obj.b" />
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: '',
b: 18
}
}
},
watch: {
obj: function (val, oldVal) {
console.log(val.a, oldVal.a, "changed")
}
}
}
</script>
复制代码
此时是监听不到对象内a属性的变化的
监听对象内层数据,需要深度监听,同时handler获取的新值和旧值相同,对象内其他值发生变化也会执行
Handler方法和deep属性
修改监听如下:
watch: {
obj: {
handler: function (val, oldVal) {
console.log(val.a, oldVal.a, "changed")
},
deep: true
}
}
复制代码
deep属性深入监听,层层遍历,属性b的修改也会触发handler方法,性能开销特别大。而且拿不到oldVal值,因为指针指向相同。
引用类型的值需要computed处理
优化:使用计算属性给引用类型的值进行处理,实现深拷贝之后,完美拿到oldVal值
computed: {
objClone () {
return JSON.parse(JSON.stringify(this.obj))
}
},
watch: {
objClone: {
handler: function (val, oldVal) {
console.log(val.a, oldVal.a, "changed")
},
deep: true
}
}
复制代码
使用字符串直接监听a的变化
这样其他属性的变化也不会触发对a的监听
watch: {
"obj.a": function (val, oldVal) {
console.log(val, oldVal, "changed")
}
}
复制代码
immediate属性
监听开始之后被立即执行,但是此时一定要注意oldVal值为undefined,oldVal.a直接使用会报错。
watch: {
objClone: {
handler: function (val, oldVal) {
console.log(val.a, oldVal.a, "changed")
},
deep: true,
immediate: true
}
}
复制代码
注意事项
- 不应该使用箭头函数来定义 watcher 函数,箭头函数内的this为undefined
- 新增属性this.obj.c = “”,删除属性delete this.b不会触发监听函数handler,应该使用this.delete(this.obj, “b”)
- 组件选项中的watch函数会随着组件的销毁而销毁
Vue实例方法this.$watch
实现对obj的监听
实现对obj的监听,且能获得oldVal值
<template>
<div>
<p>{{ obj.a }}</p>
<input v-model="obj.a" />
<p>{{ obj.b }}</p>
<input v-model.number="obj.b" />
</div>
</template>
<script>
let unwatch = null
export default {
data () {
return {
obj: {
a: '',
b: 18
}
}
},
mounted () {
unwatch = this.$watch(function () {
return JSON.parse(JSON.stringify(this.obj))
}, function (val, oldVal) {
console.log(val.a, oldVal.a, 'changed')
}, {
deep: true
})
},
beforeDestroy () {
unwatch()
}
}
</script>
复制代码
this.$watch监听数据变化时,当组件销毁时,需要手动注销掉watch。注销方式返回的取消观察函数,用来停止触发回调。
使用immediate属性
immediate: true时在回调函数中取消监听
立即执行,触发回调,此时要在回调中取消监听,需要添加容错,判断unwatch是否存在
mounted () {
unwatch = this.$watch(function () {
return JSON.parse(JSON.stringify(this.obj))
}, function (val, oldVal) {
if (unwatch) {
unwatch()
}
}, {
deep: true,
immediate: true
})
}
复制代码
数组响应式监听的方法
- this.$set()
- ‘push’, ‘pop’, ‘shift’, ‘unshift’, ‘splice’, ‘sort’, ‘reverse’被重写的原型方法
组件复用导致动态路由参数失效
通过watch监听$route的变化
<template>
<div></div>
</template>
<script>
export default {
data () {
return {}
},
mounted () {
console.log("mouted", this.$route.params.id)
},
watch: {
$route: function (to, from) {
console.log("watch", to.params.id)
}
}
}
</script>
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END