Vue响应式原理

80 阅读2分钟

1.数据驱动

1.数据响应式

数据模型仅仅是普通的JavaScript对象,而当我们修改数据时,视图会自动进行更新,避免了繁琐的DOM操作,提高开发效率

2.双向绑定

数据改变,视图改变;视图改变,数据也随之改变

使用v-model在表单元素上创建双向数据绑定

3.数据驱动是Vue最独特的特性之一

开发过程中仅需要关注数据本身,不需要关心数据是如何渲染到视图

2.响应式的核心原理

Vue2.x:当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setterObject.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。

function proxyData(data){
    //遍历data对象的所有属性
    Object.keys(data).forEach(key =>{
        //把data中的属性,转换成vm的setter/getter
      Object.defineProperty(vm,key,{
          enumerable:true,
          configurable:true,
          get(){
              return data[key]
          },
          set(newValue){
              if(newValue === data[key]){
                return
              }
              data[key] = newValue
              //数据更改,更新DOM值
              document.querySelector('#app').textContent = data[key]
          }
      })
    })
}

Vue3.x: 通过Proxy实现,直接监听对象,而非属性(ES6中新增,IE无法使用)

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

let vm = new Proxy(data,{
    //执行代理行为的函数
    //当访问vm的成员会执行
    get(target,key){
        return target[key]
    },
    //当设置vm的成员会执行
    set(target,key,newValue){
        if(target[key] === newValue){
            return
        }
        target[key] = newValue
        document.querySelector('#app').textContent = target[key]
    }
})

3.发布订阅模式

存在订阅者、发布者、信号中心

我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”(publish)一个信号,其他任务可以向信号中心订阅(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做“发布订阅模式”

class EventEmitter{
    constructor(){
        this.subs = Object.create(null)
    }
    //注册事件
    $on(eventType,handler){
        this.subs[eventType] = thsi.subs[eventType] || []
        this.subs[eventType].push(handler)
    }
    //触发事件
    $emit(eventType){
        if(this.subs[eventType]){
            this.subs[eventType].forEach(handler => {
                handler()
            });
        }
    }
}

4.观察者模式 观察者(订阅者)--watcher

update:事件发生时,具体要做的事

目标(发布者)--Dep

subs数组:存储所有的观察者

addSub():添加观察者

notify():当事件发生,调用所有观察者的update()方法

class Dep{
    //发布者-目标
    constructor () {
        //记录所有的订阅者
        this.subs = []
    }
    //添加订阅者
    addSub(sub){
        if(sub & sub.update){
            this.subs.push(sub)
        }
    }
    //发布通知
    notify(){
        this.subs.forEach(sub =>{
            sub.update()
        })
    }
}

class Watcher{
    update(){
        console.log('update')
    }
}

image.png

5.模拟Vue响应式原理

1.整体结构

image.png

Vue:负责把data的成员注入到Vue实例,并且转换成getter/setter,Vue内部会调用Observer,Compiler

Observer:数据劫持,对data中的数据进行监听,如果数据发生变化会获取到最新的值并通知Dep

Compiler:解析每个元素中的指令与差值表达式,并替换成相应的数据

Dep:添加观察者,当数据发生变化时通知所有观察者

Watcher:通过update方法更新视图