
简单点讲,在Vue的底层实现上,Vue将模板编译成虚拟DOM渲染函数。结合Vue自带的响应系统,在状态改变时,Vue能够智能地计算出重新渲染组件的最小代价并应到DOM *** 作上。
patch(也叫做patching算法):虚拟DOM最核心的部分,它可以将vnode渲染成真实的DOM,这个过程是对比新旧虚拟节点之间有哪些不同,然后根据对比结果找出需要更新的的节点进行更新。这点我们从单词含义就可以看出, patch本身就有补丁、修补的意思,其实际作用是在现有DOM上进行修改来实现更新视图的目的。Vue的Virtual DOM Patching算法是基于Snabbdom的实现,并在些基础上作了很多的调整和改进
Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列 *** 作使这棵树映射到真实环境上。
虚拟DOM的最终目标是将虚拟节点渲染到视图上。但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的DOM *** 作。例如,一个ul标签下很多个li标签,其中只有一个li有变化,这种情况下如果使用新的ul去替代旧的ul,因为这些不必要的DOM *** 作而造成了性能上的浪费。
为了避免不必要的DOM *** 作,虚拟DOM在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点(oldVnode)做对比,找出真正需要更新的节点来进行DOM *** 作,从而避免 *** 作其他无需改动的DOM。
其实虚拟DOM在Vue.Js主要做了两件事:
提供与真实DOM节点所对应的虚拟节点vnode 将虚拟节点vnode和旧虚拟节点oldVnode进行对比,然后更新视图 具备跨平台的优势由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。
*** 作 DOM 慢,Js运行效率高。我们可以将DOM对比 *** 作放在Js层,提高效率。因为DOM *** 作的执行速度远不如JavaScript的运算速度快,因此,把大量的DOM *** 作搬运到JavaScript中,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM *** 作,从而显著提高性能。
Virtual DOM 本质上就是在 Js 和 DOM 之间做了一个缓存。可以类比 cpu 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 Js 和 DOM 之间加个缓存。cpu(Js)只 *** 作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)
提升渲染性能Virtual DOM的优势不在于单次的 *** 作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。
为了实现高效的DOM *** 作,一套高效的虚拟DOM diff算法显得很有必要。我们通过patch 的核心----diff 算法,找出本次DOM需要更新的节点来更新,其他的不更新。
Vue的diff算法是基于snabbdom改造过来的,仅在同级的vnode间做diff,递归地进行同级vnode的diff,最终实现整个DOM树的更新。因为跨层级的 *** 作是非常少的,忽略不计,这样时间复杂度就从O(n3)变成O(n)。
diff 算法的实现过程diff 算法本身非常复杂,实现难度很大。本文去繁就简,粗略介绍以下两个核心函数实现流程:
patch(container,vnode) :初次渲染的时候,将VDOM渲染成真正的DOM然后插入到容器里面。 patch(vnode,newVnode):再次渲染的时候,将新的vnode和旧的vnode相对比,然后之间差异应用到所构建的真正的DOM树上。function createElement(vnode) { var tag = vnode.tag var attrs = vnode.attrs || {} var children = vnode.children || [] if (!tag) { return null } // 创建真实的 DOM 元素 var elem = document.createElement(tag) // 属性 var attrname for (attrname in attrs) { if (attrs.hasOwnProperty(attrname)) { // 给 elem 添加属性 elem.setAttribute(attrname,attrs[attrname]) } } // 子元素 children.forEach(function (childVnode) { // 给 elem 添加子元素,如果还有子节点,则递归的生成子节点。 elem.appendChild(createElement(childVnode)) // 递归 }) // 返回真实的 DOM 元素 return elem} 2.patch(vnode,newVnode) 这里我们只考虑vnode与newVnode如何对比的情况:
function updateChildren(vnode,newVnode) { var children = vnode.children || [] var newChildren = newVnode.children || [] // 遍历现有的children children.forEach(function (childVnode,index) { var newChildVnode = newChildren[index] // 两者tag一样 if (childVnode.tag === newChildVnode.tag) { // 深层次对比,递归 updateChildren(childVnode,newChildVnode) } else { // 两者tag不一样 replaceNode(childVnode,newChildVnode) } })} 总结 以上是内存溢出为你收集整理的对vue虚拟dom的研究全部内容,希望文章能够帮你解决对vue虚拟dom的研究所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)