3/11 什么是virtual dom、diff算法?

前面的话

因疫情影响,小柒已经22天没碰过电脑,博客也没有更新。今天喜提充电器,无比激动!!! 小柒将继续更新博客,之前的Vue每日一题也会补起来。又可以与小伙伴们一起学习进步,开心!!!

什么是virtual dom?

virtual dom即虚拟dom,不是真实的dom。它是用js模拟的DOM结构,是一个js对象

看一下真实dom与虚拟dom的区别:

真实dom:

<div id = "main">
	<p>文本内容</p>
	<p>文本内容</p>
</div>

虚拟dom:

{
	tag: 'div',
	attributes: {
		id: 'main'
	},
	children: [
	   {
	     tag: 'p',
	     children: ['文本内容']
	   }
	   {
	   	 tag: 'p',
	   	 children: ['文本内容']
	   }
	]
}
为何会存在virtual dom?

在了解什么是虚拟dom之后,我们要知道为什么vue 2.x会加入虚拟dom。

原因:使用虚拟dom来更新dom节点,来提高渲染性能

  • 如果不使用虚拟dom,当上面的dom节点变成下面的情况时:

    <div id = "main">
    	<p>哈哈哈哈</p>
    	<p>文本内容</p>
    	<p>hhhhhhh</p>
    </div>
    

    浏览器会重新渲染整个div里面的节点,尽管第二个p节点没有变化,也会重新渲染,然后浏览器最最消耗性能的就是操作DOM

  • 如果使用虚拟dom, 将会对比DOM,只需要修改相应的部分就可以。对于上面的代码,浏览器只会重新渲染第一个p节点与第三个p节点,而不会重新渲染div中的所用节点。这个对比的过程都是基于js来计算的,计算在多次的js,也比不过一次dom操作消耗性能。

virtual dom 是如何应用的?核心API是什么?

首先 vue 的虚拟 DOM 的算法是基于snabbdom这个库进行改造的。
snabbdom中的核心api:h函数patch函数

  • h函数: 作用比较简单,根据传进来的参数来生成一个Vnode(虚拟节点)

  • patch函数: 作用通过vnode生成真实的dom。它有两个重要的函数:

    1、patch(container,vnode) :初次渲染的时候,将VDOM渲染成真正的DOM然后插入到容器里面。

    2、patch(vnode,newVnode):再次渲染的时候,将新的vnode和旧的vnode相对比,然后之间差异应用到所构建的真正的DOM树上。

patch(container,vnode): 我们通过以下模拟代码,可以了解大致过程:

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
}

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) 
       }
    }
)}
什么是diff算法?

diff算法并不是vue中新东西,其实在很多情况下我们都遇到,比如说git中的diff命令,就可以找出两个文件中不同之处。

而vue中的diff算法,其实就是用来找需要更新的节点的一个过程。vue中的diff算法是在同级比较,这里插一张网上到处都在使用的图:
在这里插入图片描述
仅在同级的vnode间做diff,递归地进行同级vnode的diff,最终实现整个DOM树的更新。

diff 算法包括几个步骤:
  • 用 JavaScript 对象结构表示 DOM 树的结构(即虚拟dom);然后用这个树构建一个真正的 DOM 树,插到文档当中。即上述提到的 patch(container,vnode)函数。
  • 当状态变更的时候,重新构造一棵新的对象树(即新的虚拟dom)。然后用新的树和旧的树进行比较,记录两棵树差异。把所记录的差异应用到所构建的真正的DOM树上,视图就更新了 。即patch(vnode,newVnode)函数。

也就是说,diff的过程就是调用patch函数,就像打补丁一样修改真实dom。

最后

Vue中是如何生成虚拟dom的,那就是render函数。渲染函数就是用来生成虚拟DOM的。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 虚拟节点(Vnode)。

Vue中使用template模板来构建应用界面,在beforeMount钩子函数之前,我们就会将模板编译成render函数,执行render函数返回虚拟DOM树。在改变DOM时,beforeUpdata钩子函数之前,就会使用diff算法来找出两份虚拟DOM之间的差异。beforeUpdata钩子函数之后便会重新渲染更新DOM。达到减少对DOM的操作,从而减少浏览器的开销,提高渲染速度,改善用户体验。(还是借用网上的图片)
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值