Vue中虚拟DOM的理解
Vue中虚拟DOM的理解
Virtual DOM
是一棵以JavaScript
对象作为基础的树,每一个节点称为VNode
,用对象属性来描述节点,实际上它是一层对真实DOM
的抽象,最终可以通过渲染操作使这棵树映射到真实环境上,简单来说Virtual DOM
就是一个Js
对象,用以描述整个文档。
描述
在浏览器中构建页面时需要使用DOM
节点描述整个文档。
<div class="root" name="root">
<p>1</p>
<div>11</div>
</div>
如果使用Js
对象去描述上述的节点以及文档,那么便类似于下面的样子,当然这不是Vue
中用以描述节点的对象,Vue
中用以描述一个节点的对象包括大量属性,例如tag
、data
、children
、text
、elm
、ns
、context
、key
、componentOptions
、componentInstance
、parent
、raw
、isStatic
、isRootInsert
、isComment
、isCloned
等等,具体的属性可以参阅Vue
源码的/dev/src/core/vdom/vnode.js
。
{
type: "tag",
tagName: "div",
attr: {
className: "root"
name: "root"
},
parent: null,
children: [{
type: "tag",
tagName: "p",
attr: {},
parent: {} /* 父节点的引用 */,
children: [{
type: "text",
tagName: "text",
parent: {} /* 父节点的引用 */,
content: "1"
}]
},{
type: "tag",
tagName: "div",
attr: {},
parent: {} /* 父节点的引用 */,
children: [{
type: "text",
tagName: "text",
parent: {} /* 父节点的引用 */,
content: "11"
}]
}]
}
在Vue
中首先会解析template
中定义的HTML
节点以及组件节点,为render
作准备,在解析的过程中会生成_c()
、_v()
等函数,其作为renderHelpers
用以创建节点,_v()
函数就是用以创建文本节点,而_c()
函数就是用以创建VNode
节点的,这个函数其实就是Vue
中定义的_createElement()
函数,通过这个函数来确定创建的是普通节点还是组件节点,具体可以在Vue
源码中/dev/src/core/vdom/create-element.js
以及/dev/src/core/vdom/create-element.js
查阅,当解析完成之后,便能够生成render
函数,而当render
函数执行后便返回了VNode
节点组成的虚拟DOM
树,树中的每一颗节点都会存储渲染的时候需要的信息,之后便是通过diff
算法以及patch
过程的createElm
或patchVnode
渲染到真实DOM
。
if (typeof tag === 'string') {
let Ctor
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
if (config.isReservedTag(tag)) {
// platform built-in elements
if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) {
warn(
`The .native modifier for v-on is only valid on components but it was used on <${tag}>.`,
context
)
}
vnode = new VNode(
config.parsePlatformTagName(tag), data, children,
undefined, undefined, context
)
} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// component
vnode = createComponent(Ctor, data, context, children, tag)
} else {
// unknown or unlisted namespaced elements
// check at runtime because it may get assigned a namespace when its
// parent normalizes children
vnode = new VNode(
tag, data, children,
undefined, undefined, context
)
}
} else {
// direct component options / constructor
vnode = createComponent(tag, data, context, children)
}
作用
渲染真实DOM
的过程中开销是很大的,例如当有时候修改了某个数据或者属性,如果直接渲染到真实DOM
上可能会引起整个DOM
树的重绘与回流,而diff
算法能够只更新修改的那部分DOM
结构而不更新整个DOM
,这里需要说明的是操作DOM
结构的速度并不慢,而性能消耗主要是在浏览器重绘与回流的操作上。
当选用diff
算法进行部分更新的时候就需要比较旧DOM
结构与新DOM
结构的不同,此时就需要VNode
来描述整个DOM
结构,首先根据真实DOM
生成Virtual DOM
,当Virtual DOM
某个节点的数据改变后会生成一个新的Vnode
,然后通过newVNode
和oldVNode
进行对比,发现有不同之处便进行patch
修改于真实DOM
,然后使旧的Virtual DOM
赋值为新的Virtual DOM
。
简单来说建立Virtual DOM
的目的是减少对于整个DOM
的操作,通过建立Virtual DOM
来追踪如何改变真实DOM
,从而实现更高效地更新节点。
使用Virtual DOM
同样也是有部分缺点,代码更多,体积更大,内存占用增大,对于小量的单一的DOM
修改使用虚拟DOM
成本反而更高,但是整体来说,使用Virtual DOM
是优点远大于缺点的。
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://juejin.im/post/6844903607913938951
https://segmentfault.com/a/1190000018211084
https://github.com/lihongxun945/myblog/issues/32
https://cloud.tencent.com/developer/article/1004551
https://www.cnblogs.com/fundebug/p/vue-virtual-dom.html
https://blog.csdn.net/u010692018/article/details/78799335/
- 关于Python语言规范你需要知道的一些小tips
- R语言可视化——REmap(路径图)
- python面向对象
- 字符串hash入门
- R语言数据处理——数据合并与追加
- python爬取链家租房之获取房屋页面的详细信息(房名,地址,房价,面积,url)
- 信用卡“坏账”客户分析(二)
- Mac上提升python运算速度-PyPy初体验
- python处理json数据(复杂的json转化成嵌套字典并处理)
- Pointer-network理论及tensorflow实战
- python3 log文件处理获取某天需要的数据
- 实战深度强化学习DQN-理论和实践
- Python 工匠:编写条件分支代码的技巧
- python3 下 Zabbix监控调用graph.get并且下载监控图
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python爬虫学习 爬取幽默笑话网站
- 如何用Python快速优雅的批量修改Word文档样式?
- 为什么MySQL不推荐使用uuid或者雪花id作为主键?
- 用Python打造一款文件搜索工具,所有功能自己定义!
- 用Python绘制诱人的桑基图,一眼看透熬夜和狗粮的秘密
- magento换域名和服务器要怎么操作
- 从零搭建SpringBoot+MyBatis+MySQL工程
- 从零搭建SpringBoot+MyBatis+MySQL
- Typescript 使用日志(干货)
- 22+ 高频实用的 JavaScript 片段 (2020年)
- VSCode 的这些黑科技 99% 的人都不知道
- YOLOv4 中的 Mish 激活函数
- pdbsplit将多个chain的pdb文件分割
- rk3399 wifi和eth0共存 调试
- 23条JavaScript初学者应知的最佳实践方法