欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue数据双向绑定原理

程序员文章站 2022-07-12 21:57:04
...

1、数据绑定渲染过程

  • 创建实例
new Vue({...})
  • 为实例中赋值el、data、methods等
this.$data = data
  • 开启observer,监听data
Object.defineProperty()
  • observer中为每一个observer中的监听属性生成对应订阅器
new Dep()
  • 在get中等待订阅者加入,set中等待数据改变并通知订阅器更新视图
  • 开启complier,创建文档碎片,将el整个劫持减少dom操作消耗
const $el = document.querySelectorAll(el)[0]
const fragment = document.createDocumentFragment()
fragement.appendChild($el)
  • 遍历fragment所有节点属性找到指令属性以及特殊符号(如{{}})生成对应订阅者
[].slice.fragment.forEach(val => {
    let attributes = val.attributes
    [].slice.attributes.forEach(attr => {
        // 获取所有节点属性,进行正则、判断等操作
        ....
        // 生成对应订阅者传入参数
        new Watcher(...)
    })
})
  • Watcher通知订阅器将自身加入(Watcher即订阅者,上面说到observer中get等待订阅者加入,可通过触发get属性)
// 通过访问触发订阅器对应get,将自身赋值给target供observer中get添加自身
target = this
let value = $vm.data[attr]
target = null
  • Watcher须有一个update方法更新该订阅器对应的视图
Class Watcher{
    constructor () {
        ...
    }
    update () {
        ...
    }
}
  • observer在get中收到则将订阅者添加进自身订阅器中
const dep = new Dep()
let value = obj[key]
Object.defineProperty(obj, key, {
    get: () => {
        target && dep.addSub(target)
    },
    set: (newVal) => {
        if (newVal !== val) {
            val = newVal
            // 数据变动通知更新视图
            dep.notify(newVal)
        }
    }
})
  • 当数据变化时触发set,触发订阅器notify方法,调用该订阅器中每一个订阅者的update方法
class Dep{
    constructor () {
        this.sub = []
    }
    notify () {
        this.sub.forEach(val => {
            val.update()
        })
    }
    addSub (target) {
        this.sub.push(target)
    }
}
  • 触发watcher中的update替换数据,完成视图渲染

总结

初始化时监听data中的属性,为每个属性添加dep,运用闭包的原理等待watcher,之后开始编译模板,生成每个特殊指令对应的Watcher,通过触发对应data中的get将Watcher添加进去,当数据发生变化时通知该数据对应的每一个watcher,触发他们的update方法,完成数据绑定