1 模板解析
将html转化成AST语法树,然后根据AST语法树使用render函数生成虚拟DOM节点
2 diff算法
使用patch对比新旧两个节点,如果两个节点的tag一致,比较两个节点的props(属性),如果新节点中相应prop值变更,将新节点的值赋给旧节点;如果新节点中有旧节点中没有的prop,则添加进旧节点中
然后对比两个节点的children,这里children有两种情况,如果旧节点的children为string,新节点也为string,那么将相应children的textcontent变为新节点的,如果旧节点为数组,那么还是将新节点的textcontent赋给旧节点;如果旧节点为string,新节点为数组,那么将旧节点的innerHTML变为空,然后遍历新节点,使用mount函数将新节点的children挂载到旧节点下;如果都是数组,对相同长度的部分进行patch比较;如果新节点child的长度大于旧节点child的长度,将超出长度部分的节点mount挂载;如果新节点child长度小于旧节点child长度,对超出长度部分的节点removeChild
3 响应式原理
const state = reactive({
count: 1
})
let activeEffect
class Dep{
subs = new Set()
depend(){
if(activeEffect){
this.subs.add(activeEffect)
}
}
notify(){
this.subs.forEach(effect=>{
effect()
})
}
}
function watchEffect(effect){
activeEffect = effect
effect()
activeEffect = null
}
let targetMap = new WeakMap()
function getDep(target,key){
const depsMap = targetMap.get(target)
if(!depsMap){
depsMap = new Map()
targetMap.set(target,depsMap)
}
let dep = depsMap.get(key)
if(!dep){
const dep =new Dep()
depsMap.set(key,dep)
}
return dep
}
let reactiveHandles = {
get(target,key,receiver){
const dep = getDep(target,key)
dep.depend()
return Reflect.get(target,key,receiver)
},
set(target,key,value,receiver){
const dep = getDep(target,key)
const result = Reflect.set(target,key,value,receiver)
dep.notify()
return result
}
}
function reactive(raw){
return new Proxy(raw,reactiveHandlers)
}
watchEffect(()=>{
console.log(state.count)
})