Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to implement a virtual DOM algorithm

2025-03-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "how to achieve a virtual DOM algorithm", the content of the article is simple and clear, easy to learn and understand, now please follow the editor's ideas slowly in depth, together to study and learn "how to achieve a virtual DOM algorithm"!

That is, the main idea of the diff algorithm of virtual DOM is:

1. Convert the virtual DOM structure into a real DOM structure and replace it with the old DOM (undefined for the first time) and render it to the page.

two。 When the state changes, a new virtual DOM tree is rendered and compared with the old virtual DOM tree, and the differences are recorded after comparison.

3. The final part of the difference will be transformed into a real DOM structure and rendered on the page.

Realize

The following situations will occur during the comparison between the old virtual node and the new virtual node. Let's take Vue as an example to see how Vue2.0 is implemented by Diff algorithm:

Compare the tags of two elements

If the label is different, replace it directly, for example, div becomes p

Div- > p >

Determine whether the tag attributes of the virtual node are equal, and if not, convert the new virtual DOM tree into a real DOM structure to replace the original node.

If (oldVnode.tag! = vnode.tag) {return oldVnode.el [XSS _ clean] .replaceChild (createElm (vnode), oldVnode.el);}

Effect picture:

Compare the text of two elements

Compare whether the text is the same when the label is the same. If the text is different, then replace the text content directly.

>

The tag of both nodes is div, so compare whether the child's virtual DOM tree is the same. If the child's tag is undefined, it means that it is a text node. At this point, you can compare whether the text of this article is consistent.

If (! oldVnode.tag) {/ / text comparison if (oldVnode.text! = vnode.text) {return (oldVnode.el.textContent = vnode.text);}}

Effect picture:

Compare tag attributes

If the two tags are the same, then comparing the attributes of the tags, when the attributes are updated, the following situations will occur through the comparison of the new and old attributes:

1. Attribute comparison

If the old virtual node has it, the new virtual node does not need to delete the attributes on the old virtual node.

Let newProps = vnode.data | | {}; / / the new attribute let el = vnode.el; / / the old one does not need to delete the attribute for (let key in oldProps) {if (! newProps [key]) {el.removeAttribute (key); / / remove the real dom attribute}}

Conversely, if the old virtual node does not have it, the new virtual node can set the new properties directly.

/ / for (let key in newProps) {el.setAttribute (key, newProps [key]);}

The corresponding source code address: src\ platforms\ web\ runtime\ modules\ attrs.js

2. Style processing

If there is a new style in the old style, then delete the old style.

-style= {color:red}

+ style= {background:red}

Let newStyle = newProps.style | | {}; let oldStyle = oldProps.style | | {}; / / some of the old styles do not delete the old style for (let key in oldStyle) {if (! newStyle [key]) {el.style [key] = "";}}

On the contrary, if the old style does not exist and the new style exists, then you can directly update the new style.

For (let key in newProps) {if (key = = "style") {for (let styleName in newProps.style) {el.style [styleName] = newProps.style [styleName];}

The corresponding source code address: src\ platforms\ web\ runtime\ modules\ style.js

3. Class name processing

For class name processing, we use the class name of the new node

-class= "title ant-title"

+ class= "title ant-mian-title"

For (let key in newProps) {if (key = = "class") {el.className = newProps.class;}

Corresponding source code address src\ platforms\ web\ runtime\ modules\ class.js

Compare sons

The process of comparing sons can be divided into the following situations:

1. The old node has a son, but the new node does not have a son. Delete the son of the old node.

If (isDef (oldCh)) {removeVnodes (oldCh, 0, oldCh.length-1)} = = if (oldChildren.length > 0) {el [XSS _ clean] = "";}

2. The old node does not have a son, but the new node has a son to traverse children and convert it into a real DOM structure to add to the page.

If (isDef (ch)) {if (isDef (oldVnode.text)) nodeOps.setTextContent (elm,'') addVnodes (elm, null, ch, 0, ch.length-1, insertedVnodeQueue)} = = if (newChildren.length > 0) {for (let I = 0; I

< newChildren.length; i++) { let child = newChildren[i]; el.appendChild(createElm(child)); } } 3、老节点有儿子,新节点有儿子 当老节点的儿子和新节点的儿子都存在并且不相等的时候,这种情况比较复杂也是diff算法的核心。 在vue2.0中比较老节点和新节点区别的时候采用了双指针的方式,通过同时向同一个方向循环老节点和新节点,只要有一个节点循环完成就结束循环。如果是老节点先结束,那么将新节点剩余的元素添加到渲染列表;如果是新节点先结束,那么将旧节点剩余的元素删除即可。 定义开头指针其中包括老节点的开始位置和结束位置,新节点的开始位置和结束位置。 let oldStartIndex = 0; //老的索引 let oldStartVnode = oldChildren[0]; //老的索引指向的节点 let oldEndIndex = oldChildren.length - 1; let oldEndVnode = oldChildren[oldEndIndex]; let newStartIndex = 0; //新的索引 let newStartVnode = newChildren[0]; //新的索引指向的节点 let newEndIndex = newChildren.length - 1; let newEndVnode = newChildren[newEndIndex]; 通过判断两个节点的key和tag是否相等来确定同一元素 function sameVnode (a, b) { return ( a.key === b.key && ( ( a.tag === b.tag && ... ) || ( ... ) ) ) } 正序排列 如果多余的节点的右边的话,那么从左往右依次判断老的开始节点和新的开始节点是否是同一节点,如果是同一节点调用patchVode方法去递归子节点,将老节点和新节点的下标加1向右移动,直到下标大于children的长度。 if (sameVnode(oldStartVnode, newStartVnode)) { patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx) oldStartVnode = oldCh[++oldStartIdx] newStartVnode = newCh[++newStartIdx] } 效果图: 如果是新节点多余添加到渲染视图,如上图从左到右对比时,g节点的下一个el是null,insertBefore相当于appendChild方法向后插入;如果是从右向左,g节点的下一个el是a,那么采用insertBefore相当于向a前面插入节点。 if (oldStartIndex >

OldEndIndex) {for (let I = newStartIndex; i newEndIdx) {for (let I = oldStartIndex; I {if (isDef (item.key)) {map [item.key] = index; / / {apur.0pl. BLV 1, 2d, d, 4, 4, 5, 5, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 5, 4, 5, 5, 4, 5, 5, 4, 5, 5, 4, 5, 4, 5, 5, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 5

If found in the old node, move the old node to before the old node starts the node

Let map = createKeyToOldIdx (oldChildren); / / there is no relationship between sons let moveIndex = map [newStartVnode.key]; / / get the key of the beginning virtual node to find if (moveIndex = = undefined) {parent.insertBefore (createElm (newStartVnode), oldStartVnode.el);} else {let moveVNode = oldChildren [moveIndex]; / / this old virtual node needs to move oldChildren [moveIndex] = null; parent.insertBefore (moveVNode.el,oldStartVnode.el) Patch (moveVNode,newStartVnode) / / compare attributes and son} newStartVnode = newChildren [+ + newStartIndex] / / keep looking inside the old one with the new one

In the process of moving, the start pointer and end pointer may point to null, if you point to null, then you can no longer compare, you can just skip it and point to the next element.

If (isUndef (oldStartVnode)) {oldStartVnode = oldCh[ + + oldStartIdx] / / Vnode has been moved left} else if (isUndef (oldEndVnode)) {oldEndVnode = oldCh [--oldEndIdx]}

Source code address: src/core/vdom/patch.js

Why use key?

If there are not many ugly words, look at the picture first.

There is key.

No key.

As shown in the figure above, the first picture shows the case with key, and the second figure shows the case without key. You can obviously see that if there is a key, you can obviously reuse the 4 nodes of key for AMagi B, C and D, and the result is to insert the newly created E node in front of the C node to complete the rendering. If there is no key, then three nodes are created, which reduces the reuse rate, and the performance is certainly not as high as that of key.

Why can't you use index as your key?

In the usual development process, index can be used as key only through static rendering of the page, and if there are complex logical changes on the page, then using index as key is equivalent to no key.

A C B B C A

As shown in the code above, nodes An and C need to be recreated after changing the positions of An and C with subscript 0 and 2, where the subscript of C is 0 and subscript An is 2. Using id or unique identifier as key is equivalent to translating the position of An and C elements. The performance of translation is higher than that of creating nodes.

There will also be unexpected problems when using index as key. If we delete node B, we initially set the value to B, and now the value becomes C.

Thank you for your reading, the above is the content of "how to achieve a virtual DOM algorithm". After the study of this article, I believe you have a deeper understanding of how to achieve a virtual DOM algorithm, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report