以下内容是个人的一些学习总结,如有不对,欢迎大佬指正。
在开始虚拟DOM之前,让我们先来了解一下真实的DOM以及浏览器是怎么进行解析的。浏览器渲染引擎工作流程大致分为以下四类:创建DOM树 -> 生成render树 -> 布局render树 -> 绘制render树
当用原生js或者jq去操作真实DOM的时候,浏览器会从构建DOM树开始从头到尾执行一遍流程。当操作次数过多时,之前计算DOM节点坐标值等都是白白浪费的性能,虚拟DOM由此诞生。
假设一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在虚拟DOM上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。
参考文档:
ps: 笔者能力有限,原谅我patch源码篇看的不是很懂!在这请尤雨溪大大收下我的膝盖。
这里大家可以自行安装。
先在element.js文件中实现如何创建虚拟DOM树。
// element.js // 虚拟DOM元素类,用来描述DOM function Element(type, props, children){ this.type = type; //节点类型 this.props = props; //属性 this.children = children; //子节点 } // 创建虚拟DOM function createElement(type, props, children){ return new Element(type, props, children); } //向外输出 export { Element, createElement } 复制代码
我们来到App.vue文件中调用createElement方法来创建一个DOM对象。
//App.vue import {createElement} from './js/element.js' let V_DOM = createElement('ul',{class:'list'},[ createElement('li', {class:'item'},['item1']), createElement('li', {class:'item'},['item2']), createElement('li', {class:'item'},['item3']) ]) //打印虚拟DOM console.log(V_DOM); 复制代码
注:因为脚手架里的App.vue的内容没有删除,这里只贴了调用到的代码。
下面我们来看看浏览器里打印出来的虚拟DOM。
// element.js function render(dom) { // 根据type类型来创建对应的元素 let el = document.createElement(dom.type); // 再去遍历props属性对象,然后给创建的元素el设置属性 for (let key in dom.props) { // 设置属性的方法 el.setAttribute(key, dom.props[key]); } // 遍历子节点 // // 如果子节点也是虚拟DOM,递归构建DOM节点 // 不是就代表是文本节点,直接创建 dom.children.forEach(child => { child = (child instanceof Element) ? render(child) : document.createTextNode(child); // 添加到对应元素内 el.appendChild(child); }); return el; } //向外输出 export { Element, createElement, render, } 复制代码
回到App.vue我们来调用render函数
import {createElement, render, renderDom} from './js/element.js' let V_DOM = createElement('ul',{class:'list'},[ createElement('li', {class:'item'},['item1']), createElement('li', {class:'item'},['item2']), createElement('li', {class:'item'},['item3']) ]) //打印虚拟DOM console.log(V_DOM); var el = render(V_DOM); console.log(el); document.body.appendChild(el); 复制代码
来看看效果图。
真实的DOM结构就构建出来了,接下来渲染到页面中。 好了,我们已经实现了模拟虚拟DOM并进行了渲染。而diff算法和patch算法才是虚拟DOM最核心的部分,笔者还在努力学习阶段。这里推荐一篇宝藏文章,这里比较详细的解析了虚拟DOM算法。如果文章有错误或者不妥之处,欢迎大家指正,谢谢。