目录
4、VNode如何生成:在Vue源码中,VNode是通过一个构造函数生成的。
一、虚拟DOM
1、虚拟DOM是什么
(1) Vue通过建立一个虚拟DOM树对真实DOM发生的变化保持追踪。
(2)一棵真实DOM树的渲染需要先解析CSS样式和DOM树,然后将其整合成一棵渲染树,再通过布局算法去计算每个节点在浏览器中的位置,最终输出到显示器上。而虚拟DOM则可以理解为保存了一棵DOM树被渲染前所包含的所有信息,这些信息可以 通过对象的形式一直保存在内存中,并通过javascript的操作进行维护
2、为什么要使用虚拟DOM
(1)浏览器显示网页的五步过程:
a、解析标签,生成元素树(DOM树)
b、解析样式,生成样式树
c、生成元素与样式的关系
d、生成元素的显示坐标
e、显示页面
若修改真实的DOM元素,那么上述5步将重新走一遍,修改几次就走几遍,性能很差。如果使用虚拟DOM,虚拟DOM存储在内存中,对每个元素的修改是在内存中进行的,修改完后,比较虚拟DOM和真实DOM的差异,当有差异时,再一次过去更新网页的显示,而不是每次都重新按照浏览器的运行过程走。
(2)虚拟DOM的优点
a、保证性能的下限:框架的虚拟DOM需要适应任何上层API可能产生的操作,它的一些DOM操作的实现必须是普适的,所以它的性能并不是最优的,但是比起粗暴的DOM操作性能要好很多,因此框架的虚拟DOM至少可以保证在不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限
b、无须手动操作DOM:只需要编写好View-Model的代码逻辑,框架会根据虚拟DOM和数据双向绑定,以可以预期的方式更新视图,极大的提高开发效率
c、跨平台:虚拟DOM本质是javascript对象,而DOM与平台强相关。相比之下虚拟DOM可以进行更方便地跨平台操作
3、Diff算法
当虚拟DOM发生改变时,为了以最小的性能开销完成更新操作,需要比较新旧虚拟DOM,用于比较的算法称为Diff算法
Diff算法本身非常复杂,实现难度很大。常用的核心函数有两个
(1)patch(container,vnode):将虚拟DOM渲染成真正的DOM。即在初次渲染的时候,将虚拟的DOM渲染成真正的DOM,然后插入到容器里面
function createElement(vnode){
var tag = vnode.tag
var attrs = vnode.attrs || {}
var children = vnode.children || []
if(!tag){
return null
}
//创建真实的DOM元素
var vm = document.createElement(tag)
//定义属性
var attrName
for(attrName in attrs){
if(attrs.hasOwnProperty(attrName)){
vm.setAttribute(attrName,attrs[attrName])
}
}
//定义子元素
children.forEach(function(childVnode){
//给vm添加子元素,如果还有子节点,则递归的生成子节点
vm.appendChild(createElement(childVnode))
})
//返回真实的DOM元素
return vm
}
(2)patch(vnode,newVnode);再次渲染的时候,将新的VNode和旧的VNode进行对比,然后将之间的差异应用到所构建的真实DOM树上。
function updateChildren(vnode,newVnode){
var children = vnode.children || []
var newChildren = newVnode.children || []
//遍历现有的children
children.forEach(function(childVnode,index){
var newChildVnode = newChildren[index]
if(childVnode.tag === newChildVnode.tag){
//深层次对比,递归
updateChildren(childVnode,newChildVnode)
}else{
//两者tag不一样,则替换
replaceNode(childVnode,newChildVnode)
}
})
}