Vue2-watch监听器-新增值响应丢失

197 阅读1分钟

问题重现

在这个示例中,通过 this.person.id = 1 直接给 person 对象添加 id 属性的方式存在一个缺陷,即这种动态添加属性的方式不会被 Vue 的响应式系统所监听。Vue 的响应式系统只能在初始化实例时对已有的属性进行监听,无法自动监听动态添加的属性。

<template>
  <div>
    <div>person:{{ person }}</div>
    <el-button @click="change">新增一个属性:this.person.id = 1</el-button> <br />
  </div>
</template>
<script>
export default {
  data() {
    return {
      person: {
        name: "oldName",
      },
    };
  },
  watch: {
    person: {
      handler(newValue) {
        console.log(newValue);
        // 输出:{id: 1, name: 'newName', get/set name}
      },
      deep: true, // 深度监听
    },
  },
  methods: {
    // 新增一个属性
    change() {
      this.person.id = 1;
      this.person.name = "newName";
    },
  },
};
</script>

解决方案

(1)$set 或者 Vue.set() 方法:使用 Vue 提供的 $set 方法或者 Vue.set 方法来设置动态添加的属性。这样可以确保动态添加的属性也被 Vue 的响应式系统所监听,从而在属性值发生变化时能够触发相应的更新。

(2) Object.assign() 方法:使用 Object.assign() 方法也可以确保对象属性的变化被正确监听。当你使用 Object.assign() 方法将新的属性合并到对象中时,Vue.js 会检测到对象的变化并触发响应式更新。

<template>
  <div>
    <div>person:{{ person }}</div>
    <el-button @click="change">新增一个属性:this.person.id = 1</el-button> <br />
    <el-button @click="change2">新增一个属性:this.person.id2 = 2</el-button> <br />
    <el-button @click="change3">新增一个属性:this.$set(this.person, "id3", 3)</el-button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      person: {
        name: "oldName",
      },
    };
  },
  watch: {
    person: {
      handler(newValue) {
        console.log(newValue);
        // button1 输出:{id: 1, name: 'newName', get/set name}
        // button2 输出:{id2: 2, name: 'newName', get/set name, get/set id2}
        // button3 输出:{id3: 3, name: 'newName', get/set name, get/set id3}
      },
      deep: true, // 深度监听
    },
  },
  methods: {
    // 新增一个属性
    change() {
      this.person.id = 1;
      this.person.name = "newName";
    },
    change2() {
      this.person.id2 = 2;
      this.person.name = "newName2";
      // case 1. Object.assign()
      this.person = Object.assign({}, this.person);
    },
    change3() {
      // case 2.  this.$set()
      this.$set(this.person, "id3", 3);
    },
  },
};
</script>