Vue2-watch监听器-新旧值相同问题

125 阅读1分钟

问题重现

在以下案例中,使用 watch 来深度监控整个 person 对象时存在 person.name 改变前和改变后的值都是一样的问题。这是因为 Vue 的响应性系统无法检测对象内部属性的变化,只能检测对象引用的变化,因此直接监听整个 person 对象时可能无法正确触发。

<template>
  <div>
    <el-button @click="changeName">改变</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      person: {
        name: "oldName",
      },
    };
  },
  watch: {
    person: {
      handler(newValue, oldValue) {
        console.log(oldValue.name + "-->" + newValue.name);
        // 输出: newName-->newName
      },
      deep: true,
    },
  },
  methods: {
    changeName() {
      this.person.name = "newName";
    },
  },
};
</script>

解决方案

(1)序列化与反序列化:代码行数少,但可能导致性能问题和丢失原型链。在处理特殊值(如 undefinedNaN )时存在问题,通常情况下不太推荐使用。

(2)深拷贝:在大型项目中执行效率更高,尤其是对比 JSON.parse(),更具优势。

<template>
  <div>
    <el-button @click="changeName">改变</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      person: {
        name: "oldName",
      },
    };
  },
  watch: {
    // case 1: 使用序列化与反序列化
    newPerson: {
      handler(newValue, oldValue) {
        console.log("newPerson:" + oldValue.name + "-->" + newValue.name);
        // 输出: newPerson:oldName-->newName
      },
      deep: true,
    },
    // case 2: 深拷贝
    newPerson2: {
      handler(newValue, oldValue) {
        console.log("newPerson2:" + oldValue.name + "-->" + newValue.name);
        // 输出: newPerson2:oldName-->newName
      },
      deep: true,
    },
  },
  methods: {
    changeName() {
      this.person.name = "newName";
    },
  },
  computed: {
    // 使用计算属性进行深拷贝
    newPerson() {
      return JSON.parse(JSON.stringify(this.person));
    },
    newPerson2() {
      return this.$lodash.cloneDeep(this.person);
    },
  },
};
</script>