vue diff algorithm and virtual dom knowledge collation (12) patch refinement comparison new sub-nodes

In the above, we have written several treatments for the same node in the patch function, and the simple ones have been written, but the most troublesome child node comparison is left. Both
new and old nodes have child nodes that need to be refined.

Let's first change the entry file index.js code under src to this

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

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

const vnode = h("section", {
    
    }, [
  h("p", {
    
    key:"a"}, "a"),
  h("p", {
    
    key:"b"}, "b"),
  h("p", {
    
    key:"c"}, "c")
]);

patch( container, vnode)

const btn = document.getElementById("btn");
const vnode1 = h("section", {
    
    },[
  h("p", {
    
    key:"a"}, "a"),
  h("p", {
    
    key:"b"}, "b"),
  h("p", {
    
    key:"c"}, "c"),
  h("p", {
    
    key:"d"}, "d")
]);

btn.onclick = function(){
    
    
  patch( vnode, vnode1)
}

The new node has one more child node than the old node.
There are three cases for updating child nodes here.

In fact, the logic to deal with our last extra node will be relatively simple, because its nodes are traversed one by one based on the new node.
If there is, it is good to add it.

And the function of our key is that if the first child node, the old and new nodes are both li, one content is c and the other content is a, if you have no key for both nodes, then he will confirm that the key and label name are the same because the label names are both Li key is not set, it is undefined, then he will judge that it is the same node but the text is different, so he will replace your a text with c,
but if you set the key, he will not mess with your things but judge seriously

Then we can write the most complicated code. When both old and new nodes have child nodes,
insert image description here
we first write the code as follows

//当新旧节点都有子节点
//遍历写节点的子元素
newVnode.children.map(news => {
    
    
    //定义 isExist  判断新节点中有没有和旧节点一样的元素
    let isExist = false;
    //遍历旧节点子集
    oldVnode.children.map(old => {
    
    
        //判断  如果有一模一样的元素  什么都不用做
        if(old.sel == news.sel &&old.key == news.key) {
    
    
            isExist = true;
        }
    })
    //判断  如果在旧节点中没有找到相同的节点 就输出出来
    if(!isExist){
    
    
        console.log(news);
    }
})

Here we first traverse all the child nodes of the new node and then traverse all the child nodes of the old node to judge each new node to see if there are any child nodes of the old node that are the same as the current node. If not, we will output it and then we
run Project
insert image description here
Then we click to change dom,
insert image description here
here the node whose key is d is output.
We see index.js,
insert image description here
we can clearly see that there is indeed only d, and the same element cannot be found in the old node

Then we can further rewrite the code like this

//当新旧节点都有子节点
//定义un用于记录当前更新的元素下标
let un = 0;
//遍历写节点的子元素
newVnode.children.map((news,index) => {
    
    
    //定义 isExist  判断新节点中有没有和旧节点一样的元素
    let isExist = false;
    //遍历旧节点子集
    oldVnode.children.map(old => {
    
    
        //判断  如果有一模一样的元素  什么都不用做
        if(old.sel == news.sel &&old.key == news.key) {
    
    
            isExist = true;
        }
    })
    //判断  如果在旧节点中没有找到相同的节点 就输出出来
    if(!isExist){
    
    
        //通过createElement将虚拟节点变成真正的孤儿节点
        let dom = createElement(news);
        //当当前下标的子节点的elm属性记录上这个新创建的孤儿节点
        news.elm = dom;
        //判断un是不是已经大于了子节点创的   如果是 表示这个下标在老节点找不到
        if(un < oldVnode.children.length) {
    
    
            //在老节点对应un下标的前面插入这个节点
            oldVnode.elm.insertBefore(dom, oldVnode.children[un].elm);
        }else{
    
    
            //直接在老节点的最后面插入
            oldVnode.elm.appendChild(dom);
        }
    }else{
    
    
        //否则就表示 本次循环中 子元素找到了相同的元素 将un+1
        un++;
    }
})

We record the subscript through un and then we loop through the new node and define isExist in the variable of the new node, which is used to record whether the current node has the same

Then traverse the old node and find out whether it is the same as the child element of the new node in the traversal of the old node.
For example, our new node is abcd and the old node is abc. Then the first time I traverse the child node of the new node is a, and it will cycle through the old node. The child node of the new node is the same as the a of the old node for the first time.
After the condition is met, isExist will be copied as true to record
this. You don’t have to worry about the second time b enters the loop. The code declared by isExist will innovate and execute it Still the initial value is false,
then go out of the cycle of the old node and still in the cycle of the new node, or the node a. For example, we judge isExist.
If it is not false, it means that both the new node and the old node have this element. We will add one to un to record this node. has been recorded

Then the only difference is that the d of the new node
comes in because it can’t find the same one. At the end of the judgment, isExist is still false.
Then we still use createElement to turn this virtual node into a real orphan node
, and then the news records d itself because it It is the subscript of the child node of our loop new node that is the element of the current loop.
We directly store the newly created orphan node in the elm of the current virtual node
and then judge
whether un is greater than the number of child nodes of the old node.

If it is not greater than directly insert in front of the sub-node of the new node un subscript
, for example, if
the old node is abc and
the new node is adbc
, the first time a and a come in,
isExist is true un++ ,
now un is 1
, and the second time d is not found To the same, it will be executed to determine whether un is greater than the number of old nodes.
The old node has three child elements un is 1. Obviously un is smaller than the subset of old nodes,
then execute
oldVnode.elm.insertBefore(dom, oldVnode.children[un]. elm);
get the real dom node of the old node as the parent by using the elm of the node, and call insertBefore to insert the orphan node created with the d virtual node in front of the unsubscripted node of the old node, then the subscript 1 of the old node is the b node Because the subscript starts from zero,
the old node becomes adbc at this time.
According to my current path, when I judge that un is larger than the subset of the old node,
then I directly use appendChild to insert it into the elm of the old node. At the end,
we run the project
insert image description here
and click to update the dom,
insert image description here
our d will go up

insert image description here
Let's change the order now
and modify the index.js code as follows

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

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

const vnode = h("section", {
    
    }, [
  h("p", {
    
    key:"a"}, "a"),
  h("p", {
    
    key:"b"}, "b"),
  h("p", {
    
    key:"c"}, "c")
]);

patch( container, vnode)

const btn = document.getElementById("btn");
const vnode1 = h("section", {
    
    },[
  h("p", {
    
    key:"a"}, "a"),
  h("p", {
    
    key:"d"}, "d"),
  h("p", {
    
    key:"b"}, "b"),
  h("p", {
    
    key:"c"}, "c")
]);

btn.onclick = function(){
    
    
  patch( vnode, vnode1)
}

This is our example above.
We run the project
insert image description here
and click to change the dom
insert image description here
without any problems.

So the question is, what if the order is exchanged?

We change the index.js code as follows

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

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

const vnode = h("section", {
    
    }, [
  h("p", {
    
    key:"a"}, "a"),
  h("p", {
    
    key:"b"}, "b"),
  h("p", {
    
    key:"c"}, "c")
]);

patch( container, vnode)

const btn = document.getElementById("btn");
const vnode1 = h("section", {
    
    },[
  h("p", {
    
    key:"a"}, "a"),
  h("p", {
    
    key:"c"}, "c"),
  h("p", {
    
    key:"b"}, "b")
]);

btn.onclick = function(){
    
    
  patch( vnode, vnode1)
}

We change the order of b and c
, but we click now, it has no effect
insert image description here
because we only consider the addition of elements and have not dealt with the adjustment of old nodes.
Next, we will continue to deal with the node changes of old nodes.

Guess you like

Origin blog.csdn.net/weixin_45966674/article/details/130855321