Skip to content

Commit

Permalink
1.6.Vue虚拟DOM解析-Virtual Dom实现和Dom diff算法
Browse files Browse the repository at this point in the history
  • Loading branch information
yzsunlei committed Dec 2, 2019
1 parent 4bda6be commit 9fcbf6c
Showing 1 changed file with 119 additions and 0 deletions.
119 changes: 119 additions & 0 deletions 1.6.Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
## 关于VNode
* 在浏览器中我们可以通过js来操作DOM,但是这样的操作性能很差,因为真正的DOM元素非常庞大,于是Virtual Dom应运而生。
可以这样理解,Virtual Dom就是在js中模拟DOM对象树来优化DOM操作的一种技术或思路。

* 下面先来看看Vue中的Virtual Dom,源码位置在`src/core/vdom/vnode.js`
```vuejs
export default class VNode {
tag: string | void;
data: VNodeData | void;
children: ?Array<VNode>;
text: string | void;
elm: Node | void;
ns: string | void;
context: Component | void;
key: string | number | void;
componentOptions: VNodeComponentOptions | void;
componentInstance: Component | void;
parent: VNode | void;
//...
constructor (
tag?: string, // vNode的标签,例如div、p等标签
data?: VNodeData, // vNode上的data值,包括其所有的class、attribute属性、style属性
children?: ?Array<VNode>, // vNode上的子节点
text?: string, // 文本
elm?: Node, // vNode上对应的真实dom元素
context?: Component, // vdom的上下文
componentOptions?: VNodeComponentOptions,
asyncFactory?: Function
) {
this.tag = tag
this.data = data
this.children = children
this.text = text
this.elm = elm
this.ns = undefined
this.context = context
//...
}
//...
}
```
* 从上面源码可以看出,Virtual Dom相对浏览器中的真实Dom要简单得多。其实Vue中的Virtual Dom就是把真实Dom中一些常用的属性类型,
再加上Vue里面的一些配置项组成的。

* Vue中的Virtual Dom不仅对真实浏览器Dom进行简化外,还对不同场景进行了Virtual Dom的分类。下面是EmptyVNode、TextVNode、
CloneVNode的创建,源码位置在`src/core/vdom/vnode.js`
```vuejs
// EmptyVNode
export const createEmptyVNode = (text: string = '') => {
const node = new VNode()
node.text = text
node.isComment = true
return node
}
// TextVNode
export function createTextVNode (val: string | number) {
return new VNode(undefined, undefined, undefined, String(val))
}
// CloneVNode
export function cloneVNode (vnode: VNode): VNode {
const cloned = new VNode(
vnode.tag,
vnode.data,
vnode.children && vnode.children.slice(),
vnode.text,
vnode.elm,
vnode.context,
vnode.componentOptions,
vnode.asyncFactory
)
cloned.ns = vnode.ns
cloned.isStatic = vnode.isStatic
cloned.key = vnode.key
cloned.isComment = vnode.isComment
cloned.fnContext = vnode.fnContext
cloned.fnOptions = vnode.fnOptions
cloned.fnScopeId = vnode.fnScopeId
cloned.asyncMeta = vnode.asyncMeta
cloned.isCloned = true
return cloned
}
```
* 关于Virtual Dom的分类,除了上面三种外, 还有ElementVnode,ComponentVnode等。

* 关于VNode的创建这里就不多说,在"Vue模板编译-AST生成Render字符串"那一节内容中我们就说了生成Render字符串中_c就是
createElement创建VNode,还不清楚的可以回看一下。

## DOM diff原理
* 比较两棵DOM树的差异是 `Virtual DOM` 最核心的部分,这也是所谓的 `Virtual DOM` 的 diff 算法。 它的作用就是根据
两个虚拟对象创建出描述改变内容的补丁,将这个补丁用来更新DOM。

* 两个Dom树的完全的 diff 算法是一个时间复杂度为 O(n^3) 的问题,但实际上在前端当中,很少会跨越层级地移动DOM元素。
即Virtual DOM 只会对同一个层级的元素进行对比,这样算法复杂度就可以达到 O(n)。


## Patch 补丁更新


## VNode生命周期


## 总结一下
* 最后,在这里总结一下Vue中Virtual Dom执行过程:

> 1.用JS对象模拟DOM树,即调用createElement生成VNode
> 2.比较两棵虚拟DOM树的差异,
> 3.把差异应用到真正的DOM树上

## 相关资料
* [https://juejin.im/post/5c8e5e4951882545c109ae9c](https://juejin.im/post/5c8e5e4951882545c109ae9c)
* [https://segmentfault.com/a/1190000008291645](https://segmentfault.com/a/1190000008291645)
* [https://github.com/livoras/blog/issues/13](https://github.com/livoras/blog/issues/13)
* [https://github.com/liutao/vue2.0-source/blob/master/vdom%E2%80%94%E2%80%94VNode.md](https://github.com/liutao/vue2.0-source/blob/master/vdom%E2%80%94%E2%80%94VNode.md)

0 comments on commit 9fcbf6c

Please sign in to comment.