星星博客 »  > 

Vue 响应式——模拟封装Vue(二)

Vue 响应式——模拟封装Vue

    • Dep
    • watcher
    • Watcher 的调用
        • 实现v-model的双向数据绑定

Dep

Dep这个类的作用,是收集依赖,发送通知。
也就是在data的getter中 添加观察者,以及通知watcher
该类有三个成员,一个属性和两个方法:

  • subs 观察者数组
  • addSub 添加观察者方法
  • notify 发送通知
class Dep {
    constructor() {
        this.subs = []
    }
    // 添加观察者
    addSub(sub) {
        if (sub && sub.update) {
            this.subs.push(sub)
        }
    }
    // 发送通知
    notify() {
        this.subs.forEach(sub => {
            sub.update()
        })
    }
}

watcher

功能:

  • 当数据变化触发依赖, dep 通知所有的 Watcher 实例更新视图
  • 自身实例化的时候往dep对象中添加自己
class Watcher {
    constructor (vm,key,cb){
        this.vm = vm
        this.key = key
        this.cb = cb

        // 添加Dep静态属性target,值就是当前watcher实例
        Dep.target = this
        // 触发get
        this.oldValue = vm[key]
        Dep.target = null
    }

    update(){
        let newValue = this.vm[this.key]
        if( this.oldValue === newValue){
            return
        }
        this.cb(newValue)
    }
}

Watcher 的调用

watcher的作用是用于更新视图,所以我们可以在compiler 中的 更新视图的操作中创建 watcher 对象。
比如 在处理插值表达式的函数中

    // 用于编译文本节点
    compileText(node) {
        // 判断文件节点中的内容是不是插值表达式
        let reg = /\{\{(.+?)\}\}/
        let value = node.textContent
        if (reg.test(value)) {
            // 获取括号分组内的字符
            let key = RegExp.$1.trim()
            // 替换掉插值表达式的内容
            node.textContent = value.replace(reg, this.vm[key])

            new Watcher(this.vm,key,(newValue)=>{
                console.log(newValue);
                node.textContent = newValue
            })
        }
    }

改造 compiler 的update方法,给指令更新方法中添加 watcher

    // 定义update函数来执行不同指令的更新操作
    update(node, key, attrName) {
        let updateFn = this[attrName + 'Updater']
        updateFn && updateFn.call(this, node, this.vm[key], key)
    }
    // 处理 v-text 指令
    textUpdater(node, value,key) {
        node.textContent = value
        new Watcher(this.vm, key, (newValue) => {
            node.textContent = newValue
        })
    }
    // v-model
    modelUpdater(node, value, key) {
        node.value = value
        new Watcher(this.vm, key, (newValue) => {
            node.value = newValue
        })
    }

实现v-model的双向数据绑定

    // v-model
    modelUpdater(node, value, key) {
        node.value = value
        new Watcher(this.vm, key, (newValue) => {
            node.value = newValue
        })
        // 实现视图更新,更新数据
        node.addEventListener('input', () => {
            this.vm[key] = node.value
        })
    }

到此为止,简易的vue响应式原理封装完成。

相关文章