Vue 数据响应式

72 阅读3分钟

一、什么是数据响应式?

  • 对外界的变化做出反应即为响应式。
  • const vm = new Vue({data:{n: 0}}),当修改 vm.n 或 data.n 时,render(data…) 中的 n 就会做出相应的响应,这就是 vue 的 数据响应式。
  • vm相当于data的代理

二、如何实现数据响应式?

1.通过getter和setter修改对象属性实现数据响应

getter 是获取某个特定属性的值的方法; setter 是设定某个属性的值的方法

用代码说明一下:

let obj1 = {
  姓: "高",
  名: "圆圆",
  age: 18
}

声明一个对象,如果我想得到该对象的姓名,可以在该对象里再添加一个名为“姓名”的函数,调用它即可:

let obj1 = {
  姓: "高",
  名: "圆圆",
  姓名(){
    return this.姓 + this.名
  },
  age: 18
}
console.log(obj1.姓名()) //打印出 高圆圆

使用 getter 也可以达到相同的效果:

let obj1 = {
  姓: "高",
  名: "圆圆",
  get 姓名(){
    return this.姓 + this.名
  },
  age: 18
}
console.log(obj1.姓名)  //打印出 高圆圆

getter 的用法就是这样,通俗来说,就是一个调用时不需要加括号的函数

同理,setter 的用法也大致相同:

let obj1 = {
  姓: "高",
  名: "圆圆",
  get 姓名() {
    return this.姓 + this.名;
  },
  set 姓名(xxx){
    this.姓 = xxx[0]
    this.名 = xxx.slice(1)
  },
  age: 18
}
obj1.姓名 = '刘诗诗'
console.log(`姓 ${obj1.姓},名 ${obj1.名}`) //打印出  姓 刘,名 诗诗

用 = xxx 触发 set 函数

注意:  “姓名” 并不是一个真实的属性,因为 obj1 在定义时并没有写“姓名”这个属性,这个意思是说我们可以通过 get 和 set 对“姓名”属性进行读和写,但是并不存在一个叫“姓名” 的属性。

2.Object.defineProperty

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

例如在对象 obj1 中增加 getter、setter

let _xxx = 0;//可声明一个局部变量或者全局变量来使用,不可直接用 xxx
Object.defineProperty(obj1, "xxx", { 
  get() {
    return _xxx;//新定义的xxx是不存在的,不能在get|set里return xxx,会死循环
  },
  set(newValue) {
    _xxx = newValue;
  }
});

Object.defineProperty存在一些问题

  1. Vue只会检查第⼀层属性
  2. 必须要有‘n’,才能代理和监听obj.n,没有会出现警告

解决方法

使用Vue.set或this.$set

Vue.set和this.$set作用

  • 新增key
  • 自动创建代理和监听(如果没有创建过)
  • 触发更新UI(但不会立刻更新)

3.使用代理

vm=new Vue({data:myData}),让vm成为myData的代理(proxy),会对myData的所有属性进行监控

监控目的:防止myData的属性变了,vm不知道

vm知道属性改变才可以调用render(data),UI=render(data)

三、数组变异

data中有数组怎么办?

vue对数组进行了改变,给数组加了一层原型,在其中Vue修改了7个方法覆盖了之前数组原型的7个方法。调用这些Vue新定义的方法时,在这些新方法里Vue会加上对新添的元素的监听(相当于进行了set操作),把新数据也进行代理,这样vue就能重新监测到数组的变化了更新UI操作

  1. push()
  2. pop()
  3. shift()
  4. unshift()
  5. splice()
  6. sort()
  7. reverse()

四、总结

对象中新增的key

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

数组中新增key

  • 也可用set来新增key,更新UI
  • 不过尤雨溪修改了7个API方便对数组进行增删
  • 这7个API会自动处理监听和代理,并更新UI

结论:数组新增key最好通过7个API