function createApp(rootComponent) {
return {
mount(rootContainer) {
const context = rootComponent.setup();
let isMounted = false;
let preSubTree;
effectWatch(() => {
if (!isMounted) {
rootContainer.innerHTML = "";
isMounted = true;
const subTree = rootComponent.render(context);
mountElement(subTree, rootContainer);
preSubTree = subTree;
} else {
//update
const subTree = rootComponent.render(context);
patch(preSubTree, subTree);
preSubTree = subTree;
}
});
},
};
}
虚拟dom第一次要去挂载,挂载之后就是走更新流程,要进行新旧vdom的diff算法,也就是patch函数:
//patch
function patch(n1, n2) {
console.log("patch");
// 1.tag
if (n1.tag !== n2.tag) {
n1.el.replaceWith(document.createElement(n2.tag));
} else {
//细节!!!
const el = (n2.el = n1.el);
// 2.props
const oldProps = n1.props || {};
const newProps = n2.props || {};
if (oldProps && newProps) {
Object.keys(newProps).forEach((key) => {
const newVal = newProps[key];
const oldVal = oldProps[key];
if (newVal !== oldVal) {
el.setAttribute(key, newVal);
}
});
}
if (oldProps) {
Object.keys(oldProps).forEach((key) => {
if (!newProps[key]) {
el.removeAttribute(key);
}
});
}
// 3.children 数组或字符串
const oldChildren = n1.children;
const newChildren = n2.children;
if (typeof newChildren === "string") {
if (typeof oldChildren === "string") {
if (newChildren !== oldChildren) {
el.textContent = newChildren;
}
} else {
el.textContent = newChildren;
}
} else {
if (typeof oldChildren === "string") {
el.innerHTML = "";
newChildren.forEach((child) => {
mountElement(child, el);
});
} else {
//处理公共的部分
const length = Math.min(oldChildren.length, newChildren.length);
for (let i = 0; i < length; i++) {
patch(oldChildren[i], newChildren[i]);
}
//新的长
if (newChildren.length > length) {
newChildren.slice(oldChildren.length).forEach((child) => {
mountElement(child, el);
});
//老的长
} else if (oldChildren.length > length) {
for (let i = length; i < oldChildren.length; i++) {
oldChildren.slice(newChildren.length).forEach((child) => {
el.removeChild(child.el);
});
}
}
}
}
}
}
参考:
https://dafunk.gitee.io/views/vue/mini-vue-reactive.html https://github.com/mewcoder/codebase/tree/main/mini-vue3 https://github.com/ReySun/vue3-deep-dive-width-evan-you