1 Introduction
In the previous article describes the VNode
time we said, VNode
the biggest purpose is to generate real change in the data before and after DOM
the virtual corresponding DOM
node, and then you can compare the two old and new VNode
, to find out where the differences, there are differences then update DOM
the node, in order to reach the final minimum operating real DOM
purpose of updating the view. The contrast of old and new two VNode
and find out the differences of the process is called DOM-Diff
process. DOM-Diff
When the entire virtual algorithm DOM
of the core, then the next, we start to source code, in-depth look at Vue
the DOM-Diff
process is like.
2. patch
In the Vue
middle, the DOM-Diff
process is called patch
process. patch, meaning "patch", referring to the old VNode
patch, patch resulting in a new VNode
, very image of Kazakhstan. No matter what it is called, its essence is to compare the old and new two VNode
processes. We study the following patch
when the process must grasp such an idea: the so-called old VNode
(that is oldVNode
) is the virtual before the data change view corresponding DOM
node, and the new VNode
virtual after data changes to be rendered new view corresponding DOM
node , so we need to generate a new VNode
basis, compared to the old oldVNode
, if the new VNode
on some nodes and the old oldVNode
on not, then the old oldVNode
on add to; if the new VNode
on no node and the old oldVNode
on there , then in the old oldVNode
removed on; if some nodes in the new VNode
and old oldVNode
on there, then a new VNode
subject, updating old oldVNode
, so that new and VNode
different.
Maybe you feel a little bit around, it does not matter, we're talking plainly, you can interpret it this way: Suppose you have an old computer is now on the electronic version of the document, this time the boss gave you a new sheet of paper documents, and both of these documents tell you that most of the content is the same, so you fresh paper version of the document shall prevail, the paper version of the document to do a new electronic version of the document sent to the owner. For this task At this point, you should have two solutions: One option is whether it's an old document content is what, all deleted, and then knock against the new version of a paper document into a word by word, this program is no fee brain is tired by the point can solve the problem. While another program is based on the new paper version of the document as a benchmark, compared to the old look of the new electronic version of the document with the paper version of the document What are the differences, if there are certain parts in the new documentation and no documentation old , then put them together in the old part of the document inside; if certain parts of the document did not and the old in the new document in there, then delete these portions in the old documentation; if some parts of the old and the new documentation have, then compare to see if there needs to be updated, last updated look in the old document, reach the final version into the hands of the same with paper documentation, the perfect solution.
Contrast the above two schemes, and obviously you Vue
as clever, will choose the second option. The second program in the electronic version of the old document that has been rendered on the corresponding view oldVNode
, the new version of the document corresponding to the paper is to be rendered in the view of the new VNode
. In a word: a new VNode basis, the transformation of the old oldVNode make it like new VNode, this is the patch process to do things .
Having said that, it sounds like a very complex feeling like, it is not true, we think about it, the whole patch
is nothing more than doing three things:
- Create a node: new
VNode
there while the oldoldVNode
is not, in the oldoldVNode
creation. - To delete a node: new
VNode
no old onesoldVNode
have it from the oldoldVNode
deletion. - Update node: new
VNode
and oldoldVNode
in both, with regard to a newVNode
subject, updating oldoldVNode
.
OK, here, you're right Vue
in the patch
process of understanding half, Next, we analyzed one by one, look Vue
for three things above all how to do.
3. Create a node
In the last article we analyzed, VNode
the class can be described six types of nodes, but in fact only three types of nodes can be created and inserted into the DOM
middle, they are: element nodes, text nodes, comment nodes. So Vue
when you create a node will determine the new VNode
have in the old oldVNode
not in this node is part of what type of nodes to invoke a different method to create and inserted into the DOM
middle.
In fact, it is also difficult to determine, since it features three types of nodes is very evident in how to judge when the source:
// 源码位置: /src/core/vdom/patch.js
function createElm (vnode, parentElm, refElm) {
const data = vnode.data
const children = vnode.children
const tag = vnode.tag
if (isDef(tag)) {
vnode.elm = nodeOps.createElement(tag, vnode) // 创建元素节点
createChildren(vnode, children, insertedVnodeQueue) // 创建元素节点的子节点
insert(parentElm, vnode.elm, refElm) // 插入到DOM中
} else if (isTrue(vnode.isComment)) {
vnode.elm = nodeOps.createComment(vnode.text) // 创建注释节点
insert(parentElm, vnode.elm, refElm) // 插入到DOM中
} else {
vnode.elm = nodeOps.createTextNode(vnode.text) // 创建文本节点
insert(parentElm, vnode.elm, refElm) // 插入到DOM中
}
}
From the above code, we can see:
- Determining whether the element node simply determines
VNode
whether the node has atag
tab. If there istag
property that is considered to be an element node, then call thecreateElement
method creates an element node, usually there will be an element node child node, then recursively traverse all the child nodes created, all sub-nodes created after the goodinsert
into the current element node inside, finally current element node intoDOM
the. - Determine whether the comment node, just judge
VNode
ofisComment
whether the property istrue
to, if it istrue
compared to comment node, then call thecreateComment
method to create a comment node, and then inserted into theDOM
middle. - If the node is neither an element nor comment nodes, it is considered a text node, then call the
createTextNode
method to create a text node, and then inserted into theDOM
middle.
Code
nodeOps
isVue
to cross-platform compatibility, all nodes operate the package, for examplenodeOps.createTextNode()
in the browser equivalent todocument.createTextNode()
This completes the operation of creating a node, the entire flow chart is as follows:
4. Delete Node
If some of the new node and then VNode
is not in the old oldVNode
there, then these need to nodes from the old oldVNode
deletion. Delete nodes is very simple, just call on the parent element to be deleted node removeChild
method can be. Source as follows:
function removeNode (el) {
const parent = nodeOps.parentNode(el) // 获取父节点
if (isDef(parent)) {
nodeOps.removeChild(parent, el) // 调用父节点的removeChild方法
}
}
5. Update node
Creating nodes and delete nodes are relatively simple, and update the node is relatively more complicated, but in fact is not too much complicated, just sort out the logic will be able to understand.
Updates node is when some of the nodes in the new VNode
and the old oldVNode
in there, we need to carefully compare, find a different place to be updated.
Before we update the node, we first introduce the concept of a small, static node is what? We look at an example:
<p>我是不会变化的文字</p>
Above this node which contains only the text, without any variable variables, which means that, regardless of the data and then how changes, as long as the node for the first time rendering, and then later on it will never change, because it does not contain any variable, so any changes in the data occur nothing to do with it. We call this node is called a static node.
OK, with this concept we were beginning to update the node. When we need to update the node judges the following three cases and dealt with separately:
If
VNode
andoldVNode
are static nodesWe say, static node data regardless of any change has nothing to do with it, so are static node, then skip directly without treatment.
If
VNode
a text nodeIf
VNode
a text node that is represented in this node contains only plain text, you can simply look atoldVNode
whether it is a text node, and if so, whether it is to compare two different text, different if putoldVNode
in the text into withVNode
the text the same. IfoldVNode
not a text node, then no matter what it is, a direct callsetTextNode
method turning it into text nodes and text content withVNode
the same.If
VNode
is an element nodeIf
VNode
is an element node, then subdivided the following two situations:The node has children
If you include the child nodes within the new node, then the time to look at the old node contains child nodes, if a node in the old also contains a child node, it needs updating child nodes recursively contrast; if the old node is not included in child node, then the old node there may be empty node or text node, if the old node is an empty node new node to put in the child node creates a node is then inserted into the inside of the old, if the old node is text node, put the empty text, and then create a new child node node in a node is then inserted into the old inside.
The node has no child node
If the node does not contain child nodes, while it is not a text node, it shows that the node is an empty node, it is easy to handle, there are no matter what's before the old node, can be emptied directly.
OK, finished with more than three cases, the basic completion of the update even if a node, then we look at is how to achieve specific source, the source code is as follows:
// 更新节点
function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
// vnode与oldVnode是否完全一样?若是,退出程序
if (oldVnode === vnode) {
return
}
const elm = vnode.elm = oldVnode.elm
// vnode与oldVnode是否都是静态节点?若是,退出程序
if (isTrue(vnode.isStatic) &&
isTrue(oldVnode.isStatic) &&
vnode.key === oldVnode.key &&
(isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
) {
return
}
const oldCh = oldVnode.children
const ch = vnode.children
// vnode有text属性?若没有:
if (isUndef(vnode.text)) {
// vnode的子节点与oldVnode的子节点是否都存在?
if (isDef(oldCh) && isDef(ch)) {
// 若都存在,判断子节点是否相同,不同则更新子节点
if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
}
// 若只有vnode的子节点存在
else if (isDef(ch)) {
/**
* 判断oldVnode是否有文本?
* 若没有,则把vnode的子节点添加到真实DOM中
* 若有,则清空Dom中的文本,再把vnode的子节点添加到真实DOM中
*/
if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
}
// 若只有oldnode的子节点存在
else if (isDef(oldCh)) {
// 清空DOM中的子节点
removeVnodes(elm, oldCh, 0, oldCh.length - 1)
}
// 若vnode和oldnode都没有子节点,但是oldnode中有文本
else if (isDef(oldVnode.text)) {
// 清空oldnode文本
nodeOps.setTextContent(elm, '')
}
// 上面两个判断一句话概括就是,如果vnode中既没有text,也没有子节点,那么对应的oldnode中有什么就清空什么
}
// 若有,vnode的text属性与oldVnode的text属性是否相同?
else if (oldVnode.text !== vnode.text) {
// 若相同:用vnode的text替换真实DOM的文本
nodeOps.setTextContent(elm, vnode.text)
}
}
The above code comments have been written very clearly, and then we draw a flow chart to sort out the whole process flow chart is as follows:
By shining a flowchart and code, I believe that part of the logic node update you can easily understand.
In addition, you may have noticed, if the old and new VNode
in the child nodes are included, then for updating child nodes in the code calls updateChildren
the method, and the logic of this approach in the end is what we put next article expand learning.
6. Summary
In this article we introduced Vue
the DOM-Diff
algorithm: patch process. We first introduced the idea of the whole process algorithm, then combing through algorithm, to understand the whole patch
process did three things, namely: to create nodes, delete nodes, updated nodes. And a control source for everything launched a detailed study, which depicts the logic flow diagram. In addition to updating node, if the old and new VNode
in the child nodes are included, we need to update the detailed sub-nodes on the process of updating child nodes we started to learn in the next article.
(Finish)