03-Vue 响应式原理

182 阅读2分钟

目标

  • 模拟一个最小版本的 Vue

  • 响应式原理在面试的常问问题

  • 学习别人优秀的经验, 转换成自己的经验

  • 实际项目中出问题的原理层面的解决

    • 给 Vue 实例新增一个成员是否是响应式的?
    • 给属性重新赋值成对象, 是否是响应式的?
  • 为学习 Vue 源码做铺垫

数据驱动

  • 数据响应式、双向绑定、 数据驱动
  • 数据响应式
    • 数据模型仅仅是普通的 JavaScript 对象,而当我们修改数据时,视图会进行更新。避免了繁琐的DOM 操作,提高了开发效率。
  • 双向绑定
    • 数据改变, 视图改变,视图改变, 数据也随之改变
    • 我们可以使用 v-model 在表单元素上创建双向数据绑定
  • 数据驱动是 Vue 最独特的特性之一
    • 开发过程中仅需要关注数据本身, 不需要关心数据是如何渲染到视图

数据响应式的核心原理

Vue 2.x

    let data = {
      msg: 'hello',
      count:10
    }
    let vm = {}
    //  数据劫持, 当访问或者设置 vm 中的成员的时候,做一些干预操作
    Object.defineProperty(vm,'msg',{
      // 可枚举 (可遍历)
      enumerable: true,
      // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义)
      configurabel: true,
      get () {
        console.log('get',data.msg)
        return data.msg
      },
      set(newValue){
        console.log('set', newValue)
        if(newValue === data.msg) {
          return
        }
        data.msg = newValue
        document.querySelector("#app").textContent = data.msg
      }
    })
    vm.msg = 'hello world'
    console.log(vm.msg)

如果一个对象中有多个属性需要转换getter/setter 方法

通过 Object.key 遍历实现多个属性响应式方法。

总结: vue2.0 版本的响应式原理就是通过 object.defineProperty 的 get 和 set 方法实现的。

  let data = {
   msg: 'hello',
   count: 10
 }
 let vm = {}

 proxyData(data)

 function proxyData(data) {
   Object.keys(data).forEach(key => {
     Object.defineProperty(vm, key, {
       // 可枚举 (可遍历)
       enumerable: true,
       // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义)
       configurabel: true,

       get(){
         console.log('get: ',key, data[key])
         return data[key]
       },
       set(newValue){
         console.log('set:' , key, newValue)
         if(newValue = data[key]){
           return 
         }
         data[key] = newValue
         // 数据更改,更新 DOM 的值
         document.querySelector("#app").textContent = 20
       } 
       
     })
   })
 }

Vue3.0 响应式原理

  • MDN-Proxy :用于创建一个对象的代理,从而实现基础操作的拦截和自定义(如属性查找,赋值,枚举,函数调用等)
  • 直接监听对象而非属性
  • ES6 新增 IE 不支持,性能由浏览器变化
  • 总结: vue3.0 响应式原理, 主要是通过 proxy 的 get/set 方法实现
    let data = {
      msg: 'hello',
      count: 0
    }
    let vm = new Proxy(data,{
      // 执行代理行为的函数
      // 当访问 vm 的成员会执行
      get(target,key){
        console.log('get,key',key, target[key])
      },
      set(target,key,newValue){
        console.log('set,key',key,newValue)
        if(target[key]=== newValue){
          return 
        }
        target[key] = newValue
        document.getElementById("app").textContent = target[key]
      }
    })
    vm.msg = 'hello Word'
    console.log(vm.msg)