Bootstrap

vue源码--变化侦测

vue源码–变化侦测

1.什么是渲染
  将dom数据输出到页面展示的过程叫做渲染。
2.变化侦测
  vue渲染实现:vue将页面模板数据(即data对象的数据),通过“变化侦测”输出到dom,然后渲染页面。
  什么是变化侦测?意指:监听到模板数据状态改变并将新状态输出到dom。具体流程为模板数据状态改变时,将状态刷新到虚拟dom(即vue组件data),然后将虚拟dom中的差异化数据刷新到dom。
  为什么引入虚拟dom?如果模板数据直接绑定dom节点,当模板数据改变时直接修改所有关联节点,这种监测粒度过细,依赖追踪产生的内存开销较大。为了解决这一问题引入虚拟dom概念,即将状态绑定到一个组件,状态变化时通知组件更新数据。
3.变化侦测代码实现:
   实现思路:通过Observer构造vue对象 , 对象所有属性添加getter,setter方法并将该对象的依赖存入依赖dep(dep中包含该对象的所有依赖和相关操作函数),只有通过get,set调用的改变才能被vue监听到触发变化侦测,对象的第一个改变$.watcher中的update方法,后续 dep.notify() 层层调用

*构造vue对象*
class Observer {
    constructor(value) {
        this.value = value
        if(!Array.isArray(value) {
            this.walk(value)
        }
    }
    walk (obj) {
        const keys = Object.keys(obj)
        for(let i = 0; i < keys.length; i++) {// 所有对象初始化加上getter,setter函数
            definedReactive(obj, keys[i], obj[keys[i]])
        }
    }
}

function definedReactive(data, key, value) {
	// 递归,子属性也加上getter,setter函数
    if(typeof val === 'object') { 
        new Observer(value)
    }
    let dep = new Dep()  //依赖于当前对象的数组
    Object.defineProperty(data, key, {  //javaScript原生对象定义
        enumberable: true,
        configurable: true,
        get: function () {
            dep.depend()
            return value
        },
        set: function (newVal) {
            if(value === newVal) {   
                return 
            }
            value = newVal  
            dep.notify()  
        }
    })
}

vue依赖管理类

class Dep {
    constructor () {
        this.subs = []    //存放所有依赖的数组
    }
    addSub () {
        this.subs.push(sub)
    },
    remove () {
        remove(this.subs, sub) 
    },
    depend () {
        if(window.target) {
            this.addSub(window.target)   //window.target 是this,watcher的上下文
        }
    },
    notify () {  // 通知所有依赖更新状态
        const subs = this.subs.slice()
        for(let i = 0, l = subs.length; i < l; i ++) {
            subs[i].update()      
        }
    }
}
function remove(arr, item) {
    if(arr.length) {
        const index = arr.indexOf(item)
        if(index > -1) {
            return arr.splice(index, 1)
        }
        
    }
}

watcher类:

class Watcher {
    constructor (vm, expOrFn, cb) {
        this.vm = vm
        this.getter = parsePath(expOrFn)
        this.cb = cb
        this.value = this.get()
    }
    get() {
        window.target = this
        let value = this.getter.call(this.vm, this.vm)
        window.target = undefined
        return value
    }
    update() {  //  第一个组件直接调用update函数,引发层层调用
        const oldValue = this.value
        this.value = this.get()
        this.cb.call(this.vm, this.value, oldValue)
    }
}

*注释: Object.defineProperty //javaScript原生对象定义
this.getter.call(this.vm, this.vm) this.vm对象绑定this.getter函数并调用

;