Vue2如何监听数据变化

423 阅读1分钟

声明本文不是教考点, 是通过代码, 一步步让你更明白是怎么实现的

Vue怎么实现响应式的

核心api defineProperty

基础版

  // vue中的data
    const data = {
      name: 'xue',
      age: 24
    }

    const updateView = () => {
      console.log('更新了视图')
    }

    const definedReactive = (obj, key, value) => {
      Object.defineProperty(obj, key, {
        get: ()=>{
          return value
        },
        set: val=>{
          if(val !== value) {
            value = val
            updateView()
          }
        }
      })
    }
    // 数据监听
    const observe = (obj)=>{
      if(typeof obj !== 'object' || obj === null) {
        return obj
      }
      Object.keys(obj).forEach(key=>{
        definedReactive(obj, key, obj[key])
      })
    }

    observe(data)


    data.age = 25 // 过年了得加一岁了

如何实现 深度监听


  // vue中的data
const data = {
  name: 'xue',
  age: 24,
  userInfo: {
    name: 'xue ji hong',
    company: 'mockuai'
  }
}
const definedReactive = (obj, key, value) => {
  observe(value)
  Object.defineProperty(obj, key, {
    get: ()=>{
      return value
    },
    set: val=>{
      if(val !== value) {
        value = val
        observe(val)
        updateView()
      }
    }
  })
}
data.userInfo.company = 'mockuai1' 
data.userInfo = {name: 'xue', company: 'mockuai2'}
data.userInfo.company = 'mockuai3'

defineProperty:

  • defineProperty 需要初始化一次性deep watch 所有的数据
  • defineProperty 无法监听 属性的新增和删除 所以需要 Vue.set 和Vue.delete来补全

数组的监听

上面说到defineProperty无法做到监听数据的新增和删除, 那么数组的push pop等操作自然不会被监听到

然后我们需要重定义数组的方法


  // vue中的data
const data = {
  name: 'xue',
  age: 24,
  userInfo: {
    name: 'xue ji hong',
    company: 'mockuai'
  },
  word: ['你好']
}

// 重定义数组方法
const oldProperty = Array.prototype
const arrProto = Object.create(oldProperty);
['pop', 'push', 'unshift', 'shift'].forEach(name=>{
  arrProto[name] = function(){
    updateView()
    return oldProperty[name].call(this, ...arguments)
  }
})

// 数据监听
const observe = (obj)=>{
  if(typeof obj !== 'object' || obj === null) {
    return obj
  }
  if(Array.isArray(obj)){
    obj.__proto__ = arrProto
  }
  Object.keys(obj).forEach(key=>{
    definedReactive(obj, key, obj[key])
  })
}

data.word.push('世界')