当前位置: 首页 > Web前端 > vue.js

关于VirtualDOM你所不知道的事(一):VirtualDOM简介

时间:2023-03-31 23:09:50 vue.js

一、前言React和Vue这两个最流行的前端框架都使用了VirtualDOM技术来提高页面渲染效率。那么,什么是虚拟DOM?它是如何提高页面渲染效率的?本系列文章将详细讲解VirtualDOM的创建过程,并实现一个简单的Diff算法来更新页面。本文内容脱离任何前端框架,只谈最纯粹的VirtualDOM。打字太累了,下面的VirtualDOM就用VD来表示。这是VD系列文章的开篇,后续会有更多文章带你深入了解VD的奥秘。2、什么是VD从本质上讲,VD只是一个简单的JS对象,至少包含三个属性:tag、props和children。不同的框架可能对这三个属性的命名略有不同,但表达的意思是一样的。它们是标签名(tag)、属性(props)和子元素对象(children)。以下是一个典型的VD对象示例:{tag:"div",props:{},children:["HelloWorld",{tag:"ul",props:{},children:[{tag:"li",props:{id:1,class:"li-1"},children:["第",1]}]}]}VD和dom对象是一一对应的,上面VD由以下HTML生成:

HelloWorld
    No.1
一个dom对象,比如li,通过标签(li)、props({id:1,class:"li-1"})和children(["第",1])是三个属性来描述。3、为什么需要VD有了VD,可以达到有效减少页面渲染次数的目的,从而提高渲染效率。我们先来看一下页面的更新一般会经历几个阶段:从上面的例子可以看出,页面的渲染会分为以下三个阶段:JS计算生成渲染树来绘制页面本例中JS计算用了691毫秒,生成渲染树用了578毫秒,绘制用了73毫秒。如果能够有效减少生成渲染树和绘制的时间,那么页面更新的效率也会相应提高。通过VD的对比,我们可以将多个操作合并为一个batch操作,从而减少dom重排的次数,从而缩短生成渲染树和绘制的时间。至于如何基于VD更高效的更新dom,是一个很有意思的话题,以后有机会我会另写一篇介绍。4、如何实现VD与真实DOM的映射下面我们先从如何生成VD说起。借助JSX编译器,可以将文件中的HTML转化为一个函数,然后利用该函数生成VD。看下面的例子:functionrender(){return(
HelloWorld
    No.1
);}这个函数用JSX编译后,会输出如下内容:functionrender(){returnh('div',null,'HelloWorld',h('ul',null,h('li',{id:'1','class':'li-1'},'\u7B2C1'))));}这里的h是一个函数,可以任意命名。这个名字是通过babel配置的://.babelrc文件{"plugins":[["transform-react-jsx",{"pragma":"h"//这里可以配置任何名字}]]}接下来,我们只需要定义h函数构造VD:functionflatten(arr){return[].concat.apply([],arr);}functionh(tag,props,...children){return{tag,props:道具||{},儿童:展平(儿童)||[]};}h函数会传入三个或更多的参数,前两个参数是一个标签名,另一个是属性对象。其他三个参数开头的参数都是children。children元素可能是数组形式,需要对数组进行一级解构。例如:functionrender(){return(
  • 0
  • {[1,2,3].map(i=>(
  • {i}
  • ))}
);}//JSX编译后函数render(){returnh('ul',null,h('li',null,'0'),/**下面的数组需要解构放置在子数组*/[1,2,3].map(i=>h('li',null,i)));}继续前面的例子。执行h函数后,最终会得到如下VD对象:{tag:"div",props:{},children:["HelloWorld",{tag:"ul",props:{},children:[{tag:"li",props:{id:1,class:"li-1"},children:["第",1]}]}]}下一步,遍历VD对象,生成真正的dom//创建dom元素functioncreateElement(vdom){//如果vdom是字符串或者数字类型,创建一个文本节点,比如“HelloWorld”if(typeofvdom==='string'||typeofvdom==='number'){returndoc.createTextNode(vdom);}const{tag,props,children}=vdom;//1.创建元素constelement=doc.createElement(tag);//2.属性赋值setProps(element,道具);//3.创建子元素//appendChild执行的时候会检查当前this是否是一个dom对象,所以需要绑定children.map(createElement).forEach(element.appendChild.bind(element));returnelement;}//属性赋值函数setProps(element,props){for(letkeyinprops){element.setAttribute(key,props[key]);}}createElement函数执行后,创建dom元素并显示在Pageisup(页面很丑,算了。。。)。五、小结本文介绍了VD的基本概念,并讲解了如何使用JSX编译HTML标签,然后生成VD,进而创建realdom的过程。下篇文章将实现一个简单的VDDiff算法,找出2个VD的不同点,并将更新后的元素映射到dom中。PS:如果想看完整代码,请看这里:代码(https://gist.github.com/dicke...参考链接:TheInnerWorkingsOfVirtualDOM(https://medium.com/@rajaraodv...preact源码学习系列之一:JSX解析与DOM渲染(https://github.com/youngwind/...-完结-来自微信公众号:有赞码农有赞云开发公众号编译综合技术大礼包,同类文章,涵盖前端,移动端,中间件,后端,架构框架,运维,大数据,测试,各种技术视频...关注《有赞云开发者》公众号,回复“科技”获取!