vue 高阶内容
vuejs
vue.js 有个几个核心思:
- 虚拟dom
- 响应式数据
- 组件通信
虚拟DOM
(Virtual-DOM)
真实DOM
与渲染流程
首先要想了解虚拟DOM,就需要了解什么是真实DOM;
如下图为webkit
渲染引擎工作流程(概括)
无论是什么浏览器的内核引擎,基本的渲染工作流程分为5个步骤:
创建DOM树 —> 创建style rules(常见css 样式树) —> 构建Render 树 —> 布局Layout —> Painting
- 第一步,构建DOM树:用HTML解析器解析HTML 标签等相关元素,构建出一颗DOM树
- 第二步,生成样式表:用css解析器,分析css文件和元素上inline样式(行内样式),生成页面的样式表;
- 第三部,构建Render树:将DOM树和样式树关联以来,构建出一颗render树(Attachment)。每个DOM节点都有一个attach方法,接受样式信息,返回一个render对象,这些render对象最终会被构建成一颗render树
- 第四步,确定节点坐标:根绝render树结构,为每个render树上的节点确定一个在显示器上的精确坐标
- 第五步,绘制页面:根据render树与节点坐标,然后调用每个节点的paint方法,将他们绘制出来
DOM
树的构建是文档加载完成开始吗?
构建DOM
树是一个渐进式的构成,为了给用户一个更好的体验,渲染引擎会将内容尽快的显示出来而不是等待所有HTML文档解析完成后才开始构建render
树和布局render
树是DOM
树和CSS
样式表构建完成后开始构建的吗?
因为浏览器的解析是渐进式的过程,所有这3个过程在实际进行的时候并不是完全独立的,会有交叉的过程,会边加载,边解析,边渲染CSS
的解析注意点?
CSS
的解析是从右往左解析嵌套的样式越多,解析的越慢JS
操作真实DOM
代价?
原生JS
操作DOM
时,浏览器会按照上面的构建顺序进行构建,当操作了10个DOM
节点的时候,浏览器在获取到第一个DOM
节点时会直接进行上述的构建顺序构建,并不会获知后面的9个需要变更的DOM
节点,当第一个执行完成后依次进行剩下的9个构建,造成了性能浪费,即使计算器硬件一直在迭代,操作的DOM的代价也是很昂贵的,频繁的操作会造成页面的卡顿,影响用的体验
Virtual-DOM
基础
虚拟DOM
的好处
虚拟DOM
是为了解决浏览器性能问题而设计出来的。如果一次操作更新10个DOM
的动作,虚拟DOM
不会立即操作DOM
,而是将这10次更新的diff
内容保存到本地一个JS
对象中,最终将这个JS
对象一次性attach
到DOM
树上,再进行后续操作,避免大量无所谓的计算量。所以用JS
对象模拟DOM
节点的好处就是页面的更新可以先全部反映在JS
对象(虚拟DOM
)上,操作内存中的JS
对象的速度显然要更快,等更新完成后,再将最终JS
对象映射到真实DOM
,有浏览器去绘制
算法实现
- 如何用
JS
对象模拟DOM
树
这是一个真实的DOM
树
1 | <div id="virtual-dom"> |
用JavaScript
来表示一个DOM节点很容易,需要记住节点的类型、属性、还有子节点:element.js
表示节点对象的代码
1 | /** |
更具element
对象的设定,则上面的DOM
结构就可以简单表示为:
1 | var el = require("./element.js") |
现在ul
就是我们用JavaScript
对象表示的DOM结构,输出查看ul
对应的数据结构:
- 渲染用
JS
表示的DOM
对象
由于这是JS
表示的DOM
对象,在浏览器中是无法表示的,因此需要将ul
渲染成页面上真实的DOM
结构需要进行渲染函数渲染:
1 | /** |
我们通过查看以上render
方法,会根据tagName
构建一个真正的DOM
节点,然后设置这个节点的属性,最后递归的把自己的子节点也构建起来.
我们将构建好的DOM
结构添加到页面body
上面,如下
1 | ulRoot = ul.render(); |
真正渲染到body
中真正的DOM
结构
- 比较两颗虚拟
DOM
树的差异-diff
算法
diff算法用来比较两颗V-dom树的差异。如果要对2颗树完全比较,那么diff算法的事件发展度为O(n^3)
, 但是对于前端来说,很少会进行跨越层级的移动DOM
元素,所以V-dom
只会对同一个层级的元素进行对比。如图所示,div
只会和同级的div
对比,第二层级的只会跟第二层级的对比,因此复杂度就降为了O(n)