1. function createApp(rootComponent) {
    2. return {
    3. mount(rootContainer) {
    4. const context = rootComponent.setup();
    5. let isMounted = false;
    6. let preSubTree;
    7. effectWatch(() => {
    8. if (!isMounted) {
    9. rootContainer.innerHTML = "";
    10. isMounted = true;
    11. const subTree = rootComponent.render(context);
    12. mountElement(subTree, rootContainer);
    13. preSubTree = subTree;
    14. } else {
    15. //update
    16. const subTree = rootComponent.render(context);
    17. patch(preSubTree, subTree);
    18. preSubTree = subTree;
    19. }
    20. });
    21. },
    22. };
    23. }

    虚拟dom第一次要去挂载,挂载之后就是走更新流程,要进行新旧vdom的diff算法,也就是patch函数:

    1. //patch
    2. function patch(n1, n2) {
    3. console.log("patch");
    4. // 1.tag
    5. if (n1.tag !== n2.tag) {
    6. n1.el.replaceWith(document.createElement(n2.tag));
    7. } else {
    8. //细节!!!
    9. const el = (n2.el = n1.el);
    10. // 2.props
    11. const oldProps = n1.props || {};
    12. const newProps = n2.props || {};
    13. if (oldProps && newProps) {
    14. Object.keys(newProps).forEach((key) => {
    15. const newVal = newProps[key];
    16. const oldVal = oldProps[key];
    17. if (newVal !== oldVal) {
    18. el.setAttribute(key, newVal);
    19. }
    20. });
    21. }
    22. if (oldProps) {
    23. Object.keys(oldProps).forEach((key) => {
    24. if (!newProps[key]) {
    25. el.removeAttribute(key);
    26. }
    27. });
    28. }
    29. // 3.children 数组或字符串
    30. const oldChildren = n1.children;
    31. const newChildren = n2.children;
    32. if (typeof newChildren === "string") {
    33. if (typeof oldChildren === "string") {
    34. if (newChildren !== oldChildren) {
    35. el.textContent = newChildren;
    36. }
    37. } else {
    38. el.textContent = newChildren;
    39. }
    40. } else {
    41. if (typeof oldChildren === "string") {
    42. el.innerHTML = "";
    43. newChildren.forEach((child) => {
    44. mountElement(child, el);
    45. });
    46. } else {
    47. //处理公共的部分
    48. const length = Math.min(oldChildren.length, newChildren.length);
    49. for (let i = 0; i < length; i++) {
    50. patch(oldChildren[i], newChildren[i]);
    51. }
    52. //新的长
    53. if (newChildren.length > length) {
    54. newChildren.slice(oldChildren.length).forEach((child) => {
    55. mountElement(child, el);
    56. });
    57. //老的长
    58. } else if (oldChildren.length > length) {
    59. for (let i = length; i < oldChildren.length; i++) {
    60. oldChildren.slice(newChildren.length).forEach((child) => {
    61. el.removeChild(child.el);
    62. });
    63. }
    64. }
    65. }
    66. }
    67. }
    68. }

    参考:

    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