Vue’s virtual DOM and Diff algorithm adds a lot of annotations and a lot of rewriting, Add many illustrations to explain the diff algorithm chapter 8 elaborates on some of the more ambiguous places the teacher said source link gitee.com/ykang2020/v…

0. Preview of article structure

0.1 How is the virtual DOM generated by the render function (h function)

Objective: Handwriting h function

0.2 Principle of diFF algorithm

Target: handwritten diff algorithm

0.3 How does the virtual DOM become the real DOM through diff

1. Introduction

1.1 the diff algorithm

Fine comparison

1.2 virtual DOM

Not in this courseHow does the DOM become a virtual DOMThis is part of the template compilation principle butVirtual nodes become DOM nodesYou can do that in diff

1.3 Relationships — Diff happens in the virtual DOM

Diff the new virtual DOM and the old virtual DOM to figure out how to minimize the number of updates that are reflected in the real DOM

2. Introduction and preparation of SNabbDOM

2.1 introduction

Snabbdom (Swedish, “speed”) is a well-known virtual DOM library, the ancestor of the Diff algorithm Vue source code reference snabbDOM source using TypeScript github.com/snabbdom/sn… Download the build version of JavaScript from NPM

npm install -D snabbdom
Copy the code

2.2 Setting up the initial Environment

1. Install snabbdom

cnpm install -S snabbdom
Copy the code

2. Install webPack5 and configure it

cnpm i -D webpack@5 webpack-cli@3 webpack-dev-server@3
Copy the code

Configuration webpack5

module.exports = {
  // Webpack5 does not need to configure mode
  / / the entry
  entry: "./src/index.js"./ / export
  output: {
    // Virtual package path, folder is not actually generated, but virtual generated on port 8080
    publicPath: "xuni".// The name of the packaged file
    filename: "bundle.js",},/ / configuration webpack - dev - server
  devServer: {
    // Static root directory
    contentBase: 'www'./ / the port number
    port: 8080,}};Copy the code

3. Copy the official demo Example

src/index.js

import {
  init,
  classModule,
  propsModule,
  styleModule,
  eventListenersModule,
  h,
} from "snabbdom";

const patch = init([
  // Init patch function with chosen modules
  classModule, // makes it easy to toggle classes
  propsModule, // for setting properties on DOM elements
  styleModule, // handles styling on elements with support for animations
  eventListenersModule, // attaches event listeners
]);

const container = document.getElementById("container");

const vnode = h("div#container.two.classes", { on: { click: function () { } } }, [
  h("span", { style: { fontWeight: "bold"}},"This is bold"),
  " and this is just normal text",
  h("a", { props: { href: "/foo"}},"I'll take you places!"),]);// Patch into empty DOM element -- This modifies the DOM as a side effect
patch(container, vnode);

const newVnode = h(
  "div#container.two.classes",
  { on: { click: function () { } } },
  [
    h(
      "span",
      { style: { fontWeight: "normal".fontStyle: "italic"}},"This is now italic type"
    ),
    " and this is still just normal text",
    h("a", { props: { href: "/bar"}},"I'll take you places!"),]);// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
Copy the code

3. Introduction and use of H function

3.1 introduction

Used to generate virtual nodes (VNodes)Attributes of a vnode

{
	children: undefined// Array of child elements
	data: {} // Attributes, styles, keys
	elm: undefined // The corresponding real DOM node (object), undefined means the node is not yet in the DOM tree
	key: // Unique identifier
	sel: "" / / selector
	text: "" // Text content
}
Copy the code

3.2 Creating a Virtual Node using the h function

// Create a virtual node
var myVnode1 = h('a', { props: { href: 'https://www.baidu.com'}},'YK bacteria')
console.log(myVnode1)
Copy the code

3.3 Use the patch function to add the DOM tree on the virtual node

// Create patch function
const patch = init([
  classModule,
  propsModule,
  styleModule,
  eventListenersModule,
]);

// Create a virtual node
var myVnode1 = h(
  "a",
  { props: { href: "https://www.baidu.com".target: "_blank"}},"YK bacteria"
);

// Put the virtual node on the tree
let container = document.getElementById("container");
patch(container, myVnode1);
Copy the code

3.4h Function nested use, get virtual DOM tree (important)

const myVnode3 = h('ul', [
  h('li'.'apple'),
  h('li'.'banana'),
  h('li'.'watermelon'),
  h('li'.'tomato'),])// Put the virtual node on the tree
let container = document.getElementById("container");
patch(container, myVnode3);
Copy the code

const myVnode3 = h('ul', [
  h('li'.'apple'),
  h('li', [
    h('div', [
      h('p'.'banana'),
      h('p'.'strawberry')
    ])
  ]),
  h('li', h('span'.'watermelon')),
  h('li'.'tomato'),])Copy the code

Write h functions by hand

vnode.js

Returns the passed parameters as an object

/** * produces a virtual node * returns * by combining the passed parameters into objects@param {string} Sel selector *@param {object} Data attribute, style *@param {Array} Children *@param {string|number} Text Indicates the text content *@param {object} The real DOM node (object) corresponding to ELM, undefined means that the node is not on the DOM tree *@returns * /
export default function(sel, data, children, text, elm) {
  const key = data.key;
  return { sel, data, children, text, elm, key };
}
Copy the code

h.js

Generates a virtual DOM tree that returns an object

import vnode from "./vnode";
/** * generates a virtual DOM tree, which returns an object * a lower-configured version of the h function, which must take three arguments@param {*} sel
 * @param {*} data
 * @param {*} c* call only three form text, array, function h * (1) h (' div ', {}, 'text') * (2) h (' div ', {}, []) * (3) h (' div ', {}, h ()) * /
export default function (sel, data, c) {
  // Check the number of parameters
  if (arguments.length ! = =3) {
    throw new Error("Please pass only three parameters!");
  }
  // Check the type of the third parameter c
  if (typeof c === "string" || typeof c === "number") {
    // The description is now a text
    return vnode(sel, data, undefined, c, undefined);
  } else if (Array.isArray(c)) {
    // Indicates array ②
    let children = [];
    // iterate over the C array
    for (let item of c) {
      if(! (typeof item === "object" && item.hasOwnProperty("sel"))) {
        throw new Error("The array passed in has items that are not functions of H.");
      }
      // Instead of executing item, collect every object in the array
      children.push(item);
    }
    return vnode(sel, data, children, undefined.undefined);
  } else if (typeof c === "object" && c.hasOwnProperty("sel")) {
    // ③ h is an object (the return value of h is an object)
    let children = [c];
    return vnode(sel, data, children, undefined.undefined);
  } else {
    throw new Error("Wrong type of argument passed!"); }}Copy the code

index.js

import h from "./my_snabbdom/h";

const myVnode1 = h("div", {}, [
  h("p", {}, "Hee hee"),
  h("p", {}, "Ha ha"),
  h("p", {}, h('span', {}, '呵呵')));console.log(myVnode1);
Copy the code

Results show

5. Handwritten diff algorithm preparation

5.1 Principle of diFF algorithm

Minimum update, key is key. The key is the unique identifier of the node, telling the Diff algorithm that they are the same DOM node before and after the change.

Only the same virtual node is used for fine comparison (add LI to UL li), otherwise it is violent to delete old li and insert new li (replace UL Li to OL).

Question: How to define the same virtual node? A: Same selectors and same keys

Comparisons are made within layers, not across layers. Even if it is the same virtual node, but across layers, diff is the violent deletion of old nodes and the insertion of new ones

5.2 Handwritten Diff preparation

5.2.1 How to define “One Node” in the source Code

5.2.2 Creating child nodes in the source code requires recursion

6. Handwritten diff — First time on a DOM treepatch(container, myVnode1)

6.0 DOM preparation

The 6.0.1 Node. The insertBefore ()

var insertedNode = parentNode.insertBefore(newNode, referenceNode);
Copy the code

ParentNode: indicates the parentNode of the newNode. NewNode: indicates the node used for insertion. ReferenceNode: NewNode will be inserted before this Node, adding a child Node Node under the current Node and placing the child Node before the reference Node.

6.0.2 Node. The appendChild ()

element.appendChild(aChild)
Copy the code

Appends a node to the end of the list of children of the specified parent node. If the node to be inserted already exists in the document tree of the current document, appendChild() will simply move it from its original location to the new location (no need to remove the node to be moved beforehand).

6.0.3 Element. TagName

Returns the label name of the current element

elementName = element.tagName
Copy the code

ElementName is a string that contains the tag name of the Element. In an HTML document, the tagName is returned in uppercase

6.0.4 Node. RemoveChild

Removes a child node from the DOM. Returns the deleted node

let oldChild = node.removeChild(child);

//OR

element.removeChild(child);
Copy the code

Child is the child to be removed. Node is the parent of the child. OldChild holds a reference to the deleted child. OldChild === child.

6.0.5/6.5.4 document. The createElement method

var element = document.createElement(tagName[, options]);
Copy the code

TagName: This method does not allow qualified names (e.g., “HTML :a”), Calling createElement() on an HTML document converts the tagName to lowercase before creating the element. In the Firefox, Opera, and Chrome kernels, CreateElement (null) equals createElement(“null”) returns the newly created Element(Element)

The 6.1 patch. Js

import vnode from "./vnode";
import createElement from "./createElement";

export default function (oldVnode, newVnode) {
  // Determine whether the first argument passed in is a DOM node or a virtual node
  if (oldVnode.sel == "" || oldVnode.sel === undefined) {
    // oldVnode is a DOM node. In this case, it must be wrapped as a virtual node
    oldVnode = vnode(
      oldVnode.tagName.toLowerCase(), // sel
      {}, // data[].// children
      undefined.// text
      oldVnode // elm
    );
  }
  // Check whether oldVnode and newVnode are the same node
  if (oldVnode.key === newVnode.key && oldVnode.sel === newVnode.sel) {
    console.log("It's the same node, it needs to be refined.");
  } else {
    console.log("Not the same node, forcibly insert new node, delete old node.");
    // Create a new virtual node as a DOM node
    // To manipulate the DOM, both are converted to DOM nodes
    let newVnodeElm = createElement(newVnode);
    let oldVnodeElm = oldVnode.elm;
    // Insert the new node before the old node
    if (newVnodeElm) {
      // Check that newVnodeElm exists and insert a new node before the old one
      oldVnodeElm.parentNode.insertBefore(newVnodeElm, oldVnodeElm);
    }
    // Delete the old nodeoldVnodeElm.parentNode.removeChild(oldVnodeElm); }}Copy the code

6.2 createElement method. Js

Create a node. Create a VNode as a DOM node

/** * Create a node. Create a VNode virtual node as a DOM node * that is orphan and does not insert *@param {object} vnode* /
export default function createElement(vnode) {
  // Create a DOM node based on the sel selector property of the virtual node. This node is now an orphan node
  let domNode = document.createElement(vnode.sel);
  // Determine whether there are child nodes or text
  if( vnode.text ! = ="" &&
    (vnode.children === undefined || vnode.children.length === 0)) {// Indicates that there are no child nodes
    domNode.innerText = vnode.text;
  } else if (Array.isArray(vnode.children) && vnode.children.length > 0) {
    // The inner node is a child node, and the node needs to be created recursively
    // go through the number group
    for (let ch of vnode.children) {
      A recursive call to createElement creates its DOM. A call to createElement means the DOM is created. And its ELM attribute points to the created DOM, but it's not on the tree, so it's an orphan node
      let chDOM = createElement(ch); // Return a text node
      console.log(ch);
      // domNode tree on text nodedomNode.appendChild(chDOM); }}// Add the ELM attribute for the virtual node
  vnode.elm = domNode;
  // Return the domNode DOM object
  return domNode;
}
Copy the code

6.3 the index. Js

import h from "./my_snabbdom/h";
import patch from "./my_snabbdom/patch";

let container = document.getElementById("container");
let btn = document.getElementById("btn");

// const myVnode1 = h("h1", {}, "hello ");

const myVnode1 = h("ul", {}, [
  h("li", {}, "A"),
  h("li", {}, "B"),
  h("li", {}, "C"),
  h("li", {}, "D"),]);/ / on the tree
patch(container, myVnode1);
Copy the code

6.4 Display Effect

7. Handle the situation that the old and new nodes are the same node

7.1 analysis

7.2 Different text situations of new and old nodes are realized

7.2.1 patch. Js

// Check whether oldVnode and newVnode are the same node
if (oldVnode.key === newVnode.key && oldVnode.sel === newVnode.sel) {
  console.log("It's the same node, it needs to be refined.");
  patchVnode(oldVnode, newVnode);
}
Copy the code

7.2.3 patchVnode. Js

export default function patchVnode(oldVnode, newVnode) {
  // 1. Check whether the old and new VNodes are the same object
  if (oldVnode === newVnode) return;
  // 2. Check whether newVndoe has a text attribute
  if( newVnode.text ! = =undefined &&
    (newVnode.children === undefined || newVnode.children.length === 0)) {// newVnode has a text attribute
    2.1 Check whether the text attribute of newVnode is the same as that of oldVnode
    if(newVnode.text ! == oldVnode.text) {// If the text in newVnode is different from the text in oldVnode, just write the new text to the old ELM.
      // If oldVnode is children, it will also disappear immediatelyoldVnode.elm.innerText = newVnode.text; }}else {
    // newVnode has no text property and children property
    // 2.2 Check whether oldVnode has the children attribute
    if(oldVnode.children ! = =undefined && oldVnode.children.length > 0) {
      // oldVnode has children attribute most complex case, new and old nodes have children
 
    } else {
      // oldVnode does not have children. NewVnode has the children attribute
      // Clear the contents of oldVnode
      oldVnode.elm.innerHTML = "";
      // Traverses the children of the new vNode virtual node, creating the DOM, and ascending the tree
      for (let ch of newVnode.children) {
        letchDOM = createElement(ch); oldVnode.elm.appendChild(chDOM); }}}}Copy the code

7.2.2 index. Js

import h from "./my_snabbdom/h";
import patch from "./my_snabbdom/patch";

let container = document.getElementById("container");
let btn = document.getElementById("btn");

const myVnode1 = h("h1", {}, "Hello");

/ / on the tree
patch(container, myVnode1);

const myVnode2 = h("ul", {}, [
  h("li", {}, "A"),
  h("li", {}, "B"),
  h("li", {}, "C"),
  h("li", {}, "D"),]); btn.onclick =function () {
  patch(myVnode1, myVnode2);
}
Copy the code

7.3 show

8. Analyze diff algorithm to update child node operations (important)

Here teacher PPT problem, ③ should not be new before but after

8.1 Circulating the four matching searches

1. Compare ① newStart with oldStart

If ① is hit, the header pointer newStart++ oldStart++ is moved after patch

if (checkSameVnode(oldStartVnode, newStartVnode)) {
    // The new and the old
    console.log("①1 New and old hit");
    OldStartVnode is now the same as newStartVnode
    patchVnode(oldStartVnode, newStartVnode);
    // Move the pointer to change the node to which the pointer points, indicating that both nodes are finished
    oldStartVnode = oldCh[++oldStartIdx];
    newStartVnode = newCh[++newStartIdx];
}
Copy the code

And if you don’t, then you go to the next situation

2. Compare ② newEnd with oldEnd

If ② is hit, newEnd– oldEnd– is moved after patch

if (checkSameVnode(oldEndVnode, newEndVnode)) {
    patchVnode(oldEndVnode, newEndVnode);
    oldEndVnode = oldCh[--oldEndIdx];
    newEndVnode = newCh[--newEndIdx];
}
Copy the code

And if you don’t, then you go to the next situation

3. Compare ③ newEnd with oldStart

If ③ is hit, move the node pointed to by the new post-newend after the old post-oldEnd

if (checkSameVnode(oldStartVnode, newEndVnode)) {
    // The new and the old
    console.log("③3 The new queen matches the old one");
    patchVnode(oldStartVnode, newEndVnode);
    // When ③ new and old hit, move the node. Move the node pointed to by the new node to the node behind the old node
    // Move node: Whenever a node is inserted that is already in the DOM tree, it will be moved
    parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
    oldStartVnode = oldCh[++oldStartIdx];
    newEndVnode = newCh[--newEndIdx];
}
Copy the code

Hit ③ complex case example — reverse order

And if you don’t, then you go to the next situation

4. Compare ④ newStart with oldEnd

If ④ is hit, move the node pointed to before oldStart to before oldStart

if (checkSameVnode(oldEndVnode, newStartVnode)) {
    // New before and old after
    console.log("④4 New before and old after hit");
    patchVnode(oldEndVnode, newStartVnode);
    // When ④ new front and old rear hit, the node should be moved. Move the node pointed to by the new front (old back) to the old front of the old node
    // Move node: Whenever a node is inserted that is already in the DOM tree, it will be moved
    parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm);
    oldEndVnode = oldCh[--oldEndIdx];
    newStartVnode = newCh[++newStartIdx];
}
Copy the code

If you miss, you miss in all four cases

5. None of the four types will traverse keys in an oldVnode

If you find it, move it. Move the pointer newStart++What is not found is the new node, which is inserted directly before all the unprocessed old nodes

// None of the four types are matched
console.log("All four missed.");
// Find a mapping object in keyMap, so you don't have to iterate over old objects every time
if(! keyMap) { keyMap = {};// Record the key of the node in oldVnode
  // Create keyMap from oldStartIdx to oldEndIdx
  for (let i = oldStartIdx; i <= oldEndIdx; i++) {
    const key = oldCh[i].key;
    if(key ! = =undefined) { keyMap[key] = i; }}}console.log(keyMap);
// Find the sequence number of the current item (newStartIdx) mapped in keyMap
const idxInOld = keyMap[newStartVnode.key];
if (idxInOld === undefined) {
  // If idxInOld is undefined, it is a new entry and needs to be inserted
  // The added item (newStartVnode) is not a real DOM node
  parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm);
} else {
  // indicates that the item is not new and needs to be moved
  const elmToMove = oldCh[idxInOld];
  patchVnode(elmToMove, newStartVnode);
  // Set this item to undefined to indicate that I am done with this item
  oldCh[idxInOld] = undefined;
  // Move, insertBefore can also move.
  parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
}

// newStartIdx++;
newStartVnode = newCh[++newStartIdx];
Copy the code

8.2 Loop End

After the end of

  1. NewVnode has a surplus

The rest of the new nodes areinsertThe old node oldEnd or before oldStart 2. The oldVnode has remaining nodes

// The loop ends
if (newStartIdx <= newEndIdx) {
  // Indicates that newVndoe has unprocessed nodes, so these nodes need to be added
  for (let i = newStartIdx; i <= newEndIdx; i++) {
    // insertBefore automatically recognizes null and automatically goes to the end of the queue, as in appendChildparentElm.insertBefore(createElement(newCh[i]), oldCh[oldStartIdx].elm); }}else if (oldStartIdx <= oldEndIdx) {
  // Indicates that the oldVnode has unprocessed nodes, so these nodes need to be deleted
  for (let i = oldStartIdx; i <= oldEndIdx; i++) {
    if(oldCh[i]) { parentElm.removeChild(oldCh[i].elm); }}}Copy the code

9. Update child nodes by hand diff

patchVnode.js

// 2.2 Check whether oldVnode has the children attribute
if(oldVnode.children ! = =undefined && oldVnode.children.length > 0) {
  // oldVnode has children attribute most complex case, new and old nodes have children
  updateChildren(oldVnode.elm, oldVnode.children, newVnode.children);
}
Copy the code

updateChildren.js

import createElement from "./createElement";
import patchVnode from "./patchVnode";
/ * * * *@param {object} ParentElm Dom node *@param {Array} OldCh oldVnode's child node array *@param {Array} NewCh An array of children of newVnode */
export default function updateChildren(parentElm, oldCh, newCh) {
  console.log("updateChildren()");
  console.log(oldCh, newCh);

  // Four Pointers
  / / the old before
  let oldStartIdx = 0;
  / / new front
  let newStartIdx = 0;
  / / after the old
  let oldEndIdx = oldCh.length - 1;
  / / new after
  let newEndIdx = newCh.length - 1;

  // The four nodes to which the pointer points
  // Old former node
  let oldStartVnode = oldCh[0];
  // Old back node
  let oldEndVnode = oldCh[oldEndIdx];
  // New front node
  let newStartVnode = newCh[0];
  // New post-node
  let newEndVnode = newCh[newEndIdx];

  let keyMap = null;

  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    console.log("** in ** loop");
    // The first step is not to judge the four hits, but to skip the items marked with undefined
    if (oldStartVnode === null || oldCh[oldStartIdx] === undefined) {
      oldStartVnode = oldCh[++oldStartIdx];
    } else if (oldEndVnode === null || oldCh[oldEndIdx] === undefined) {
      oldEndVnode = oldCh[--oldEndIdx];
    } else if (newStartVnode === null || newCh[newStartIdx] === undefined) {
      newStartVnode = newCh[++newStartIdx];
    } else if (newEndVnode === null || newCh[newEndIdx] === undefined) {
      newEndVnode = newCh[--newEndIdx];
    } else if (checkSameVnode(oldStartVnode, newStartVnode)) {
      // The new and the old
      console.log("①1 New and old hit");
      OldStartVnode is now the same as newStartVnode
      patchVnode(oldStartVnode, newStartVnode);
      // Move the pointer to change the node to which the pointer points, indicating that both nodes are finished
      oldStartVnode = oldCh[++oldStartIdx];
      newStartVnode = newCh[++newStartIdx];
    } else if (checkSameVnode(oldEndVnode, newEndVnode)) {
      // New queen and old queen
      console.log("②2 New queen and old queen hit");
      patchVnode(oldEndVnode, newEndVnode);
      oldEndVnode = oldCh[--oldEndIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (checkSameVnode(oldStartVnode, newEndVnode)) {
      // The new and the old
      console.log("③3 The new queen matches the old one");
      patchVnode(oldStartVnode, newEndVnode);
      // When ③ new and old hit, move the node. Move the node pointed to by the new node to the node behind the old node
      // Move node: Whenever a node is inserted that is already in the DOM tree, it will be moved
      parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
      oldStartVnode = oldCh[++oldStartIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (checkSameVnode(oldEndVnode, newStartVnode)) {
      // New before and old after
      console.log("④4 New before and old after hit");
      patchVnode(oldEndVnode, newStartVnode);
      // When ④ new front and old rear hit, the node should be moved. Move the node pointed to by the new front (old back) to the old front of the old node
      // Move node: Whenever a node is inserted that is already in the DOM tree, it will be moved
      parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm);
      oldEndVnode = oldCh[--oldEndIdx];
      newStartVnode = newCh[++newStartIdx];
    } else {
      // None of the four types are matched
      console.log("All four missed.");
      // Find a mapping object in keyMap, so you don't have to iterate over old objects every time
      if(! keyMap) { keyMap = {};// Record the key of the node in oldVnode
        // Create keyMap from oldStartIdx to oldEndIdx
        for (let i = oldStartIdx; i <= oldEndIdx; i++) {
          const key = oldCh[i].key;
          if(key ! = =undefined) { keyMap[key] = i; }}}console.log(keyMap);
      // Find the sequence number of the current item (newStartIdx) mapped in keyMap
      const idxInOld = keyMap[newStartVnode.key];
      if (idxInOld === undefined) {
        // If idxInOld is undefined, it is a new entry and needs to be inserted
        // The added item (newStartVnode) is not a real DOM node
        parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm);
      } else {
        // indicates that the item is not new and needs to be moved
        const elmToMove = oldCh[idxInOld];
        patchVnode(elmToMove, newStartVnode);
        // Set this item to undefined to indicate that I am done with this item
        oldCh[idxInOld] = undefined;
        // Move, insertBefore can also move.
        parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
      }

      // newStartIdx++;newStartVnode = newCh[++newStartIdx]; }}// The loop ends
  if (newStartIdx <= newEndIdx) {
    // Indicates that newVndoe has unprocessed nodes, so these nodes need to be added
    // // insert the benchmark
    // const before =
    // newCh[newEndIdx + 1] === null ? null : newCh[newEndIdx + 1].elm;
    for (let i = newStartIdx; i <= newEndIdx; i++) {
      // insertBefore automatically recognizes null and automatically goes to the end of the queue, as in appendChildparentElm.insertBefore(createElement(newCh[i]), oldCh[oldStartIdx].elm); }}else if (oldStartIdx <= oldEndIdx) {
    // Indicates that the oldVnode has unprocessed nodes, so these nodes need to be deleted
    for (let i = oldStartIdx; i <= oldEndIdx; i++) {
      if(oldCh[i]) { parentElm.removeChild(oldCh[i].elm); }}}}// Check if it is the same node
function checkSameVnode(a, b) {
  return a.sel === b.sel && a.key === b.key;
}
Copy the code

Source link gitee.com/ykang2020/v…