Vue的数据响应式初探

81 阅读2分钟

ES6中的getter setter

let Person =  {
    set name (name) {
        console.log("setter");
        this._name = name;
    }
    get name () {
        console.log("getter");
        return this._name;
    }
}

通过getter和setter设置一个伪属性,利用不同名的变量模拟对于属性的操作

注意不要写

get name(){
  return this.name
}

这种调用方式会100%爆栈

Object.defineProperty

MDN连接
Object.defineProperty()  方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

const _xxx = 0;
Object.defineProperty(obj3, "xxx", {
  get() {
    return _xxx;
  },
  set(value) {
    // 可以通过额外的操作给变量的取值和赋值进行监控
    _xxx = value;
  },
});

小结:

Object.defineProperty

  1. 可以给对象添加属性 value

  2. 可以给对象添加 getter/setter

  3. getter/setter 在定义的时候用于对属性的读写进行监控

代理(设计模式)

以Vue的声明为例const vm =new Vue(Data) 对Vue的构造对象的Data属性读写,全权由另一个对象Vue的实例vm来控制,通过vm.n 来操作 Data.n

vm = new Vue({data:myData})

  1. vm 成为 myData 的代理(proxy),对myData 的所有属性进行监控
  2. 为什么要监控,为防止 myData 的属性变了,vm 不知道
  3. vm 捕获到变化就可以重新渲染 UI = render(data)

示意图

image.png

什么是响应式

  1. 基本思想 能够对外界的对象改变做出反应,就可以称作响应式。例如Vue的数据响应,网页的响应式布局

  2. Vue的响应式 const vm = new Vue({data:{n:0}})

修改data中的n,那么对应UI中显示的n就会变化

data中的bug

如果属性一开始就不存在,就不会被监听

new Vue({
  data: {
    obj: {
      a: 0, // obj.a 会被 Vue 监听 & 代理
    },
  },
  template: `
    <div>
      {{obj.b}}
      <button @click="setB">set b</button>
    </div>
  `,
  methods: {
    setB() {
      this.obj.b = 1; //页面中什么都不会显示
    },
  },
}).$mount("#app");

解决方法

使用 Vue.set 或 this.$set

作用:

  1. 在data中新增 key
  2. 自动创建代理和监听(如果没创建过)
  3. 触发 UI 更新(不会立刻更新,副作用)

举例:this.$set(this.object,"b",100)

new Vue({
  data: {
    obj: {
      a: 0, // obj.a 会被 Vue 监听 & 代理
    },
  },
  template: `
    <div>
      {{obj.b}}
      <button @click="setB">set b</button>
    </div>
  `,
  methods: {
    setB() {
      Vue.set(this.obj, "b", 1);
      // this.$set(this.obj, 'b', 1)
    },
  },
}).$mount("#app");

变异方法

文档

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

总结

对象中新增的 key

Vue 没有办法事先监听和代理 要使用 set 来新增 key,来创建监听和代理,更新 UI 最好提前把属性都写出来,不要新增key

数组中新增的 key

也可以用 set 来新增 key,不会创建监听和代理,会更新 UI