Vue3 Options API的watch中如何结构化对比嵌套对象的新旧值
解决方案
核心思路和Vue官方给出的Composition API实现逻辑完全一致:通过在监听源阶段对响应式对象做深拷贝,让watch内部存储的新旧值指向不同引用,即可实现结构化对比。以下提供3种可直接在Options API中使用的实现方案:
方案1:基于lodash的最简实现(官方推荐)
直接复用官方思路,在Options API中通过函数形式的监听源返回深拷贝结果:
import _ from 'lodash' export default { // 其他组件配置省略 data() { return { items: { // 你的深度嵌套对象数据 } } }, watch: { // 监听源为返回深拷贝items的函数 [() => _.cloneDeep(this.items)]: { handler(newVal, oldVal) { // 直接用lodash内置深对比方法,也可替换为你自己实现的checkIfStructurallyEqual const isEqual = _.isEqual(newVal, oldVal) if (isEqual) return this.doSomething() }, deep: true } } }
方案2:无第三方依赖实现
如果不想引入lodash,可使用浏览器原生structuredClone做深拷贝,搭配你自己实现的深对比逻辑:
export default { data() { return { items: { // 嵌套数据 } } }, created() { // 手动注册watch,兼容性更强 this.$watch( () => structuredClone(this.items), (newVal, oldVal) => { const isEqual = this.checkIfStructurallyEqual(newVal, oldVal) if (isEqual) return this.doSomething() }, { deep: true } ) }, methods: { checkIfStructurallyEqual(obj1, obj2) { // 你已实现的深对比逻辑 }, doSomething() { // 业务逻辑 } } }
方案3:性能优化方案(适合超大对象场景)
如果你的嵌套对象数据量极大、深拷贝开销高,可手动维护旧值缓存,减少不必要的深拷贝次数:
import _ from 'lodash' export default { data() { return { items: { // 大体积嵌套数据 }, // 存储上一次的深拷贝结果 prevItemsCache: null } }, watch: { items: { deep: true, handler(newVal) { // 首次加载时初始化缓存 if (this.prevItemsCache === null) { this.prevItemsCache = _.cloneDeep(newVal) return } const isEqual = _.isEqual(newVal, this.prevItemsCache) if (!isEqual) { this.doSomething() // 逻辑执行完成后更新缓存 this.prevItemsCache = _.cloneDeep(newVal) } } } } }
注意事项
- 深拷贝存在固定性能开销,如果对象包含函数、Symbol、DOM节点、Error实例等特殊类型,原生
structuredClone无法正常拷贝,建议使用lodash.cloneDeep或者自定义深拷贝实现 - 所有方案的
deep: true配置不能省略,否则嵌套属性变更不会触发watch回调
内容的提问来源于stack exchange,提问作者deepanshMathur
相关产品推荐
相关产品推荐

