“This is the seventh day of my participation in the First Challenge 2022.

patch

Next, we will learn the process of VNode rendering into real DOM, but this process is complicated and also the core of Snabbdom, so we will first study the overall process analysis of patch in this section

Patch overall process analysis

  • patch (oldVnode: VNode | Element, vnode: VNode)

  • Render the contents of the new node into the real DOM, and finally return the new node as the old node for the next processing

  • Check whether the old and new VNodes have the same key and SEL.

    • If it is not the same node, delete the previous content and re-render

    • If it is the same node, check whether the VNode has text. If it does and it is different from oldVnode’s text, update the text content directly

    • If the new VNode has children, check whether the children have changed

Patch contrast VNode

Understand method entry parameters

First, let’s review the two parameters of patch function

  • OldVnode: It can be either a normal VNode object or a normal DOM object (provided at first rendering)
  • vnode

InsertedVnodeQueue: insertedVnodeQueue: insertedVnodeQueue: insertedVnodeQueue: insertedVnodeQueue: insertedVnodeQueue: insertedVnodeQueue: insertedVnodeQueue

let i: number, elm: Node, parent: Node
const insertedVnodeQueue: VNodeQueue = []
for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]()
Copy the code

OldVNode type determination and conversion

Is the first argument oldVNode passed in a VNode object? Because the first object can be either a real DOM object or a virtual DOM object

if(! isVnode(oldVnode)) { oldVnode = emptyNodeAt(oldVnode) }Copy the code

How does the isVnode function determine if it is a real DOM

IsVnode method

function isVnode (vnode: any) :vnode is VNode {
  returnvnode.sel ! = =undefined
}
Copy the code

The code here is very simple. Check whether there is sel property under VNode. We know that the object with sel selector property is vNode

Back to the code above

if(! IsVnode (oldVnode)) {oldVnode = emptyNodeAt(oldVnode) <===Copy the code

When the oldVnode we pass in is a real DOM, we convert the real DOM into a VNode object using the emptyNodeAt function

emptyNodeAt

function emptyNodeAt (elm: Element) {
    const id = elm.id ? The '#' + elm.id : ' '
    const c = elm.className ? '. ' + elm.className.split(' ').join('. ') : ' '
    return vnode(api.tagName(elm).toLowerCase() + id + c, {}, [], undefined, elm)
}
Copy the code

This method function content is relatively short, let’s analyze it a little bit!

    1. Gets the id of the elementconst id = elm.id ? '#' + elm.id : ''

    Gets the id of the element, concatenating it with # if it exists, otherwise returns an empty string

    1. Class style conversionconst c = elm.className ? '.' + elm.className.split(' ').join('.') : ''

    If a class style exists, the split method is called to split multiple class styles and convert them to a class selector, otherwise an empty string is returned

    1. Create a VNode object:return vnode(api.tagName(elm).toLowerCase() + id + c, {}, [], undefined, elm)

    Api.tagname (elm).tolowercase () + id + c splicesthe tagName, id selector, and class style together as the sel of the VNode object, followed by each passing argument to the method, and finally elm as the current corresponding DOM element.

Let’s go back to the code

Judge old and new nodes

 if (sameVnode(oldVnode, vnode)) {
  patchVnode(oldVnode, vnode, insertedVnodeQueue)
} else {
  elm = oldVnode.elm!
  parent = api.parentNode(elm) as Node

  createElm(vnode, insertedVnodeQueue)

  if(parent ! = =null) { api.insertBefore(parent, vnode.elm! , api.nextSibling(elm)) removeVnodes(parent, [oldVnode],0.0)}}Copy the code

First we use the sameVnode function to determine whether the old and new nodes are the same node

SameVnode compares whether the node functions are the same

The sameVnode function is also quite simple

function sameVnode (vnode1: VNode, vnode2: VNode) :boolean {
  return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel
}
Copy the code

Check whether the key and SEL nodes are equal

  • If it’s called from the same nodepatchVnodeFunction update node

The patchVnode function is quite complicated, so I will not talk about it first because of the number of words in this chapter

  • If it’s not a node
elm = oldVnode.elm!
parent = api.parentNode(elm) as Node

createElm(vnode, insertedVnodeQueue)

if(parent ! = =null) { api.insertBefore(parent, vnode.elm! , api.nextSibling(elm)) removeVnodes(parent, [oldVnode],0.0)}Copy the code

The DOM element corresponding to the new VNode is created and inserted into the DOM tree, and the DOM element corresponding to the old node is removed

    1. elm = oldVnode.elm!Gets the corresponding DOM element under oldVnode
    1. parent = api.parentNode(elm) as NodeObtain the corresponding parent element. The purpose of obtaining the parent element is to mount the created element to the parent element after the DOM element corresponding to the new VNode is created
    1. createElm(vnode, insertedVnodeQueue)Create the DOM element corresponding to the VNode
    1. if (parent ! == null)Determines whether the parent element is empty
    1. api.insertBefore(parent, vnode.elm! , api.nextSibling(elm))Mount the created DOM element to the DOM tree
    1. removeVnodes(parent, [oldVnode], 0, 0)Removing an old node