Vue中你不知道的watch用法

aa.jpg

当需要在数据变化时执行异步或开销较大的操作时,需要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.set(this.obj,c,)this.set(this.obj, “c”, “”)和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
喜欢就支持一下吧
点赞0 分享