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

What is the principle of Vue's diff algorithm?

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

Share

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

This article will explain in detail what the principle of Vue's diff algorithm is. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.

Mind map

0. Introduce from frequently asked questions

What is a virtual dom?

How to create a virtual dom?

How does a virtual dom render to be a real dom?

How to patch virtual dom (patch)

What are the benefits of virtual DOM? (performance)

What is the use of key in Vue, and why can't you use index?

Implementation of diff algorithm in Vue

Is the diff algorithm depth or breadth first traversal?

1. Generate virtual dom1. H method realization

Virtual dom, that is, virtual node

1. It simulates nodes in dom through the Object object of js

two。 Then it is rendered into a real dom node by a specific render method.

Eg:

Hello world

If you use the h method to generate a virtual dom:

H ('div', {id:' wrapper', class:'1'}, h ('span', {style: {color:' red'}}, 'hello'),' world')

Corresponding js objects are as follows:

Let vd = {type: 'div', props: {id:' wrapper', class:'1'}, children: [{type: 'span', props: {color:' red'}, children: [{}]}, {type:', props:'' Text: 'world'}]}

Implement an h method by yourself

Function createElement (type, props = {},... children) {/ / prevent assigning an initial value let key if no value is passed If (props.key) {key = props.key delete props.key} / / if the child node has a string type Also need to convert to virtual node children = children.map (child = > {if (typeof child = 'string') {/ / wrap child nodes that are not of node type as virtual node return vNode (undefined, child)} else {return child}} return vNode (type, props, key, children)} function vNode (type, props, key, children) Text = undefined) {return {type, props, key, children, text} 2. Render method implementation

The function of render: convert virtual dom into real dom and render it into container container

Export function render (vnode, container) {let ele = createDomElementFrom (vnode) / / convert the real node if (ele) container.appendChild (ele)} by this method

Convert the virtual dom into a real dom and insert it into the container. If the virtual dom object contains a type value, it is described as an element (createElement), otherwise it is a node type (createTextnode), and the real node is assigned to the virtual node to establish the relationship between the two.

Function createDomElementFrom (vnode) {let {type, key, props, children, text} = vnode if (type) {/ / description is a tag / / 1. Add a domElemnt attribute to the virtual element to establish a connection between the real and virtual dom, which can be used to follow the new real dom vnode.domElement = document.createElement (type) / / 2. According to the attributes of the current virtual node To match the value of the new real dom updateProperties (vnode) / / 3. The virtual nodes in children are also virtual nodes (that is, the son is recursively appended to the current element) children.forEach (childVnode = > render (childVnode, vnode.domElement))} else {/ / description is a text} return vnode.domElement} function updateProperties (newVnode, oldProps = {}) {let domElement = newVnode.domElement / real dom Let newProps = newVnode.props / / the attribute in the current virtual node / / if there is an attribute in the old one but not in the new one, it means that this attribute has been removed from for (let oldPropName in oldProps) {if (! newProps [oldPropName]) {delete domElement [oldPropName] / / New none. In order to reuse this dom, delete directly}} / / if there is style in the new one, there is also style in the old one. Style may not be the same let newStyleObj = newProps.style | | {} let oldStyleObj = oldProps.style | | {} for (let propName in oldStyleObj) {if (! newStyleObj [propName]) {domElement.style [propName] =''}} / / not in the old one The new one contains for (let newPropsName in newProps) {/ / directly overwrite the attribute if of the old node with the attribute of the new node (newPropsName = = 'style') {let styleObj = newProps.style For (let s in styleObj) {domElement.style [s] = styleObj [s]}} else {domElement [newPropsName] = newProps [newPropsName]}

Update the real dom value according to the attributes of the current virtual node

Since there are still child nodes, we also need to recursively generate the real node of the virtual dom of the child node and insert it into the current real node.

3. Render again

Just now you may be a little confused about why you want to compare the new node with the old node attribute, because this is the first rendering, now let's talk about the second rendering.

For example, now that we have built a new node newNode, we need to compare it with the old node, but not simply replace it, but need to reuse as much as possible.

First of all, judge the type of parent node, and replace it directly if it is different.

If it's the same

1. Text type, just replace the text value directly.

two。 Element type, which needs to be replaced according to the attribute

This proves the necessity of our oldProps in the render method, so here we assign the real dom of the new node to the real dom of the old node, reuse it first, and then modify it later.

UpdateProperties (newVnode, oldVNode.props)

Export function patch (oldVNode, newVnode) {/ determine whether the type is the same, but it is different to directly replace the old if (oldVNode.type! = = newVnode.type) {return oldVNode.domElement.replaceChild (createDomElementFrom (newVnode), oldVNode.domElement)} / / with the same type. And the text if (oldVNode.text) {return oldVNode.document.textContent = newVnode.text} / / type is the same, not the text, but the label, and the attribute / / 1 of the old node needs to be updated according to the attribute of the new node. Reuse the real dom let domElement of the old node = newVnode.domElement = oldVNode.domElement / / 2. Update the attribute updateProperties (newVnode, oldVNode.props) / / compare son let oldChildren = oldVNode.children let newChildren = newVnode.children / / 1 according to the latest virtual node. The old one has a son, the new one has a son if (oldChildren.length > 0 & & newChildren.length > 0) {/ / compare the two sons (very complicated)} else if (oldChildren.length > 0) {/ / 2. The old one has a son, the new one has no son domElement [XSS _ clean] =''} else if (newChildren.length > 0) {/ / 3. Added son for (let I = 0; I < newChildren.length; iTunes +) {/ / add each son to the element let ele = createDomElementFrom (newChildren [I]) domElement.appendChild (ele)}} 2. Diff algorithm

In the rendering method just now, the first is to compare the outermost elements. For the son node, it is divided into three cases.

1. The old one has a son, the new one has no son (then just set the innerHTML of the real node to empty)

two。 The old ones have no sons, the new ones have sons (then traverse the son list of the new virtual nodes and convert each of them into a real dom,append to the outermost real dom using the createElementFrom method)

3. The old has a son, the new has a son, and this is a very complicated situation, that is, the diff algorithm that we are going to talk about.

1. Optimize the common dom

Append elements before and after

Positive and reverse order elements

Middle insert element

Take the most common ul list as an example

Old virtual dom

Let oldNode = h ('div', {}, h (' li', {style: {background: 'red'}, key:' A'},'A'), h ('li', {style: {background:' blue'}, key:'B'},'A'), h ('li', {style: {background:' yellow'}, key:'C'},'C') H ('li', {style: {background:' green'}, key:'D'},'D'),) Case 1: append an element at the end (head and head are the same)

New virtual node

Let newVnode = h ('div', {}, h (' li', {style: {background: 'red'}, key:' A'},'A'), h ('li', {style: {background:' blue'}, key:'B'},'B'), h ('li', {style: {background:' yellow'}, key:'C'}, 'C1') H ('li', {style: {background:' green'}, key:'D'}, 'D1'), h (' li', {style: {background: 'black'}, key:' D'},'E'),)

Eg:

/ / compare whether the same node function isSameVnode (oldVnode, newVnode) {return oldVnode.key = = newVnode.key & & oldVnode.type = = newVnode.type} / / difffunction updateChildren (parent, oldChildren, newChildren) {/ / 1. Create the beginning pointer and end of the old node let oldStartIndex = 0 let oldStartVnode = oldChildren [oldStartIndex]; let oldEndIndex = oldChildren.length-1 let oldEndVnode = oldChildren [oldEndIndex]; / / 2. The pointer to create a new node let newStartIndex = 0 let newStartVnode = newChildren [newStartIndex]; let newEndIndex = newChildren.length-1 let newEndVnode = newChildren [newEndIndex]; / / 1. When inserting a node from behind, when you want to judge the cycle between the old child and the new child, the one who ends first will stop the loop while (oldStartIndex

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