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 {//updateconst subTree = rootComponent.render(context);patch(preSubTree, subTree);preSubTree = subTree;}});},};}
虚拟dom第一次要去挂载,挂载之后就是走更新流程,要进行新旧vdom的diff算法,也就是patch函数:
//patchfunction patch(n1, n2) {console.log("patch");// 1.tagif (n1.tag !== n2.tag) {n1.el.replaceWith(document.createElement(n2.tag));} else {//细节!!!const el = (n2.el = n1.el);// 2.propsconst 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
