Vue2 数据响应式

122 阅读2分钟

1、Vue2 数据响应式 是什么

数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。 使用vue时,只需改变数据,视图层就会获取相应的更新。

vue对data做了什么:

  1. 数据劫持:当数据变化时,我们可以做一些特定的事情
  2. 依赖收集:我们要知道那些视图层的内容(DOM)依赖了哪些数据(state)
  3. 派发更新:数据变化后,如何通知依赖这些数据的DOM

Object.definePropert用法

// 模拟 Vue 中的 data
const data = {}
// 对外不可见的内部变量
let _myName = 'Kobe'  // _myName就是代理
// 响应式监听 data 中的 name
Object.defineProperty(data, "name", {
    // 使用 data.name 时 get 方法被拦截调用,返回内部存储变量值
    get(){  // 下文中该方法统称为getter
    //在这里收集依赖
      console.log('get')
      return _myName
    },
    // 使用 data.name = xxx 修改变量时,set 方法被调用,设置内部存储变量值
    set(newVal){ // 下文中该方法统称为setter
      console.log('set')
      _myName = newVal
       //当数据变更时,通知依赖项变更UI
       
    }
})
console.log(data.name) // 输出 Kobe  get
data.name = 'Mr.Wu' // 输出 set (监听成功)

Vue使用Object.defineProperty来进行数据劫持

  • 当我们把options.data传给vue , data会被vue监听,通过Object.defineProperty给对象添加getter/setter,当我们访问data.name时,输出 get ,返回 Kobe;当 data.name = xxx 修改变量时,我们自定义了data.name取值和赋值的行为,使用自定义的gettersetter来重写了原有的行为,这也就是数据劫持的含义。
  • 为什么我们要用let _myName = 'Kobe' 代理,而不是直接return data.namedata.name = newVal?
    • 如果直接在get函数中使用return data.name这里的 data.name会再次调用get函数,这样就会陷入死循环;set也是同理;所以需要设置第三方变量 _myName来阻止死循环。

但是如果我们需要代理更多的属性,不可能给每一个属性定义一个第三方的变量,可以通过封装函数和使用闭包来解决

// value使用了参数默认值
function defineReactive(data, key, value) {
  Object.defineProperty(data, key, {
    get: function reactiveGetter() {
      return value
    },
    set: function reactiveSetter(newValue) {
      if (newValue === value) return
      value = newValue
    }
  })
}

defineReactive(obj, "a", 1) 

2、Object.defineProperty缺点

  • Object.defineProperty(obj,'n',{...})dtate 使用时必须传n
  • 只有监听的属性才能被劫持,在vue2中,数据开始就要写在data中。

3、解决

  1. 初始把date声明好,
  2. 监听新增的属性需要使用this.$set或者Vue.set
this.$set(this.object,'m',100)

4、Vue.set和this.$set的作用

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

如果data中有数组怎么办?一要新增key

  1. 用set新增key,会更新ui,但不会创建监听和代理
  2. 不过vue中有变更方法,其中7个api方便对数组进行增删,但不会自动处理监听和代理 变更方法
  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()