In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.