什么是虚拟DOM?VirtualDOM使用JS对象来描述真实的DOM(普通的JS对象,描述DOM结构)。Vue中的虚拟Dom借鉴了Snabbdom,并加入了Vue.js的特性。(借鉴模块机制、钩子函数、diff算法等,增加指令、组件机制等新特性)为什么要使用虚拟DOM,避免直接操作DOM,提高开发效率(只关注业务代码实现,不需要要注意dom浏览器兼容性问题)作为中间层可以跨平台(WebWeex移动平台SSR渲染)虚拟DOM不一定能提升性能,第一次渲染时会增加开销(需要额外维护一个layerofvirtualdom)在复杂视图的情况下提高渲染性能(频繁的dom操作,通过diff算法,比较新旧虚拟dom树的差异,更新差异)hfunctionvm=newVue({el:"#app",render(h){//h(tag,data,children)//tag元素标签,data元素属性,children数组表示子元素,string表示元素内容//returnh('h1',this.msg)//省略数据//returnh('h1',{domProps:{innerHTML:this.msg}})//dom属性//returnh('h1',{attrs:{id:"title"}},this.msg)//标签属性和dom内容letvnode=h('h1',{attrs:{id:"title"}},this.msg)console.log(vnode)返回vnode;},data:{msg:"helloworld"}})输出方法总结vm.$createElement(tag,data,children,normalizeChildren)tag标签名称或组件对象数据描述标签,可以设置DOM属性或children标签属性表示标签中的文本内容,或者子节点返回一个js对象(vnode对象)renderingpositionsupdateComponent=()=>{//这个是回调,定义在core/instance/lifecycle.jswathersurface会调用//_render或者获取虚拟dom_update将虚拟dom转化为真实的domvm._update(vm._render(),hydrating)}解析vm._render方法定位到core/instance/render.js.这个方法会获取用户传入的render,并执行它,返回一个vnode对象.$createElement当用户通过render函数时=(a,b,c,d)=>createElement(vm,a,b,c,d,true)createElement方法会处理传入的数据,pave它,然后调用_createElement方法创建一个VNode,并返回解析VNodeCreate_createElement内部判断tag,赋值给响应式组件的tag。如果children是多维数组,makeflat最后创建VNode返回解析vm._update获取到VNode对象后,通过_update渲染挂起在core/instance/lifecycle.js中加载真正的dom_update定义对于第一次渲染和数据更新操作使用vm.__patch__来对比分析新老节点vm.__patch__方法补丁函数定义在platforms/web/runtime/index.jsVue。prototype.__patch__=inBrowser?patch:nooppatch函数由createPatchFunction方法生成(该方法是高阶函数,柯里化函数)。这个方法传入一个对象对象包含基础模块和平台相关模块,如指令、ref、属性、样式、事件、转换分析等,Snabbdom没有。createPatchFunction方法位于core/vdom/patch.js中。该函数类似于Snabbdom中的init,最后返回Addedthepatchfunction,(functionreturnfunction,high-level)解析源码700行左右的patch函数,判断新节点是否存在,不存在则去掉对应老节点判断老节点是否不存在,新节点是否存在,如果存在,则调用createElm创建新的VNode,判断老节点是否存在,老节点是vnode还是真实dom,如果是vnode并且oldVnode和vnode是同一个节点,比较一下,如果不是vnode而是dom通过patchVnode,将dom转换成vnode得到vnode的父dom,确定所在的位置vnode将在那个时候被插入。分析patch函数中createElm和patchVnodecreateElm这两个方法。如果该节点已经被渲染并且有子节点,则通过createComponent克隆一份vnode来判断标签、注释节点、文本节点。1.标签:如果定义了html中不存在的标签,会发出警告。否则,创建dom元素对应的vnode,通过createElement,设置vnode作用域。非weex平台,处理childdom,调用createhook,插入label2.注释:调用createComment,插入3.文本:调用createTextNode,插入patchVnode如果是vnode,不是dom,新旧vnodekeytags相同,都有子节点然后调用patchVnode执行diff算法比较方法,内部会得到新旧vnode的子节点。判断新旧节点是否有文本,如果是文本节点则替换文本,新节点没有文本,且新旧节点都有子节点。调用updateCHildren比较和更新dom。新节点有子节点,旧节点没有子节点。检查新节点的子节点是否有重复键。旧节点是否有文本,清除文本,将新节点下的子节点转为dom。旧节点有子节点,新节点没有子节点。移除旧节点的子节点,触发remove,destoryhook旧节点有文本,清空文本,分析updateChildren如果两个vnode节点有子节点,且key标签相同,用diff算法比较子节点最大限度地重用引用地址key
