手写虚拟DOM diff算法或Vue3响应式原理实现

87 阅读1分钟

以下是手写虚拟DOM diff算法和Vue3响应式原理的实现代码:

virtual-dom-diff.js

class VNode {
    constructor(tag,props,children){
        this.tag = tag 
        this.props = props || {}
        this.children = children || []
        this.key = props?props.key :undefined
    }
}
function diff(oldVNode,newVNode){
    //1.如果标签不同,直接替换整个节点
    if(oldVNode.tag !==newVNode.tag){
        return {type:'REPLACE',node:newVNode}
    }
    //2.比较属性差异
    const  propsPatches = diffProps(oldVNode.props, newVNode.props)

    //3.比较子节点差异
    const childrenPatches = diffChildren(oldVNode.children,newVNode.children)

    return {
        type:'UPDATE',
        props:propsPatches,
        children:childrenPatches
    }
}
function diffProps(oldProps,newProps){
    const patches = {}
    //找出变化的属性
    for(const key in newProps){
        if(oldProps[key] !==newProps[key]){
            patches[key] = newProps[key]
        }
    }
    //找出被删除的属性
    for(const key in oldProps){
        if(!newProps.hasOwnProperty(key)){
            patches[key] = null
        }
    }
    return patches
}

function diffChildren(oldChildren,newChildren){
    const patches = []
    const len = Math.max(oldChildren.length,newChildren.length)
    for(let i = 0 ; i<len;i++){
        if(!oldChildren[i]){
            patches.push({type:'ADD',node:newChildren[i]})
        }else if(!newChildren[i]){
            patches.push({type:'REMOVE',index:i})   
        }else{
            patches.push(diff(oldChildren[i],newChildren[i]))
        }
    }
    return patches
}

虚拟DOM diff算法实现功能:

创建虚拟DOM节点类VNode

实现节点差异比较(diff函数)

属性差异比较(diffProps)

子节点差异比较(diffChildren)

vue3-reactive.js

const targetMap = new WeakMap()
let activeEffect = null

function track(target ,key ){
    if(!activeEffect) return 
    let depsMap = targetMap.get(target)
    if(!depsMap){
        targetMap.set(target,(depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if(!dep){
        depsMap.set(key,(dep = new Set()))
    }
    dep.add(activeEffect)
}
function trigger(target ,key){
    const depsMap =targetMap.get(target)
    if(!depsMap) return 
    const dep = depsMap.get(key)
    if(dep){
        dep.forEach(effect => effect())
    }
}
function reactive(obj){
    return new Proxy(obj,{
        get(target,key,receiver){
            track(target,key)
            return Reflect.get(target,key,receiver)
        },
        set(target,key,value,receiver){
            const oldValue = target[key]
            const result = Reflect.set(target,key,value,receiver)
            if(oldValue !==value){
                trigger(target,key)
            }
            return result
        }
    })
}
function effect(fn){
    activeEffect = fn
    fn()
    activeEffect = null 
}

Vue3响应式原理实现功能:

使用Proxy实现数据劫持

依赖收集系统(targetMap)

追踪依赖(track)

触发更新(trigger)

响应式对象创建(reactive)

副作用函数(effect)