我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Vue中Virtual DOM和Diff原理及实现方法是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Vue中Virtual DOM和Diff原理及实现方法是什么

本篇内容介绍了“Vue中Virtual DOM和Diff原理及实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1. vdom

vdom即虚拟DOM,将DOM映射为JS对象,结合diff算法更新DOM

以下为DOM

<div id="app">  <div class="home">home</div></div>

映射成VDOM

{  tag: 'div',  attrs: {    id: 'app'  },  children: [    {      tag: 'div',      attrs: {        class: 'home'      },      children: [        {          tag: undefined,          attrs: undefined,          text: 'home',          children: undefined        }      ]    }  ]}

通过这个vdom实现简单的render函数,可以通过js操作修改dom

<template>  <div id="app">    <div v-for="item in arr">{{ item.name }} : {{ item.id }}</div>  </div>  <button id="btn">reRender</button></template>
let app = document.getElementById('app')let data = {  arr: [       { name: 'a', id: 1 },    { name: 'b', id: 2 },    { name: 'c', id: 3 },  ]}function render(data) {  app.innerHtml = ''  let children = []  data.forEach(item => {    let el = document.createElement("div")    el.innerHtml = `${ item.name } : ${item.id}`    app.appendChild(el)  })  }// testrender(data.arr) // 首次渲染let btn = document.getElementById('btn')btn.onClick = () => {  data.arr[2].id++ // 修改关联数据  render(data.arr) // 重新渲染:暴力刷新DOM,没有diff,实际上只用更新最后一个div就行}

使用snabbdom实现VDOM

snabbldom是简易实现vdom功能的库,有两个核心api:h函数和patch函数

h(tag, attrs, children) // 创建vnodepatch(vnode, newVnode) // 对vnode进行diff后挂载到真实dom上

结合hpatch实现render渲染函数

let app = document.getElementById('app')let vnode;function render(data) {  let newVnode = h('div', { class: 'wrap' }, data.forEach(item => {      return h('div', {}, `${item.name} : ${item.id}`)    })  )  patch(vnode, newVnode)  vnode = newVnode}render(data.arr) // 首次渲染let btn = document.getElementById('btn')btn.onClick = () => {  data.arr[2].id++ // 修改关联数据  render(data.arr) // 重新渲染:在patch函数里经过vdom的diff后再挂载到真实dom,这里只更新最后一个div}

2. Diff

为了尽量减少DOM操作,需要通过diff对比新旧vnode,针对更改的地方进行更新DOM,而非替换整个DOM

大体思路为:

  • 对新旧两个节点调用patch函数

  • 进来先判断两个节点是否为同一类型,具体是对比keytagdata等属性

  • 若不为同一类型,那么基于新节点创建dom之后作替换

  • 若为同一类型,那么调用patchVnode函数

  • 进来先判断两个节点是文本节点的话,那么就作文本内容替换

  • 否则判断是否都有子节点,都有的话调用updateChildren函数,通过首尾四个指针对子节点数组进行diff更新;若旧节点有子节点,新节点没有,这时就删除子节点;若旧节点无子节点,新节点有,这时基于新节点创建dom作替换即可

通过createElment函数,将VDOM转为真实DOM

function createElement(vnode) {  if(vnode.text) return document.createTextNode(vnode) // 文本节点      let { tag, attrs, children } = vnode    let el = document.createElement(tag) // tag    for(let key of attrs){ // attrs    el.setAttribute(key, attrs[key])  }    children.forEach(childVnode => { // children    el.appendChild(createElement(childVnode))   })  vnode.el = el  return el}

通过patch函数,执行diff更新操作

判断vnodenewVnode是否为同一类型节点,是则继续递归对比子节点,否则直接替换

function patch(vnode, newVnode) {  if (isSameNode(vnode, newVnode)) patchVnode(vnode, newVnode)  else replaceVnode(vnode, newVnode)}function replaceVnode(vnode, newVnode) {  let el = vnode.el // 旧节点  let parentEl = api.getParentNode(el) // 获取父节点  api.insertBefore(parentEl, createElement(newVnode), api.getNextSibling(el)) // 插入新节点  api.removeChild(parentEl, el) // 删除旧节点}function isSameNode(vnode, newVnode) {  return (    vnode.key == newVnode.key && // key是否相同    vnode.tag == newVnode.tag && // tag是否相同    isDef(vnode.data) == isDef(newVnode.data) // 是否都定义了data    // &&... 其他条件  )}function patchVnode(vnode, newVnode) {  let el = newVnode.el = vnode.el // 获取当前旧节点对应的dom,并赋值给新节点的el  // 1.都为文本节点,且文本不一样  if (vnode.text && newVnode.text && vnode.text != newVnode.text)    return api.setElText(el, newVnode.text) // 替换文本    let ch = vnode.children  let newCh = newVnode.children  if (ch && newCh) return updateChildren(el, ch, newCh) // 2.都有子节点,递归对比  if (ch) return api.removeChild(el) // 3.vnode有子节点,newVnode无,删除子节点  return replaceVnode(vnode, newVnode) // 4. newNode有子节点,vnode无,替换即可}

updateChildren实现比较复杂,使用首尾四指针进行vnodenewVnode的对比

function updateChildren(el, ch, newCh) {  // 子节点下标  let l = 0  let r = ch.length - 1  let newL = 0  let newR = newCh.length - 1  // 子节点  let lNode = ch[l]  let rNode = ch[r]  let newLNode = newCh[newL]  let newRNode = newCh[newR]  while (l <= r && newL <= newR) {    if (!lNode || !rNode || !newLNode || !newRNode) { // 边界处理      if (!lNode) lNode = ch[++l]      if (!rNode) rNode = ch[--r]      if (!newLNode) newLNode = newCh[++newL]      if (!newRNode) newRNode = newCh[--newR]      continue    }        // 新旧子节点首尾指针对比 l*newL、r*newR、l*newR、r*newL    if (isSameNode(lNode, newLNode)) {      patchVnode(lNode, newLNode)      lNode = ch[++l]      newLNode = newCh[++newL]      continue    }    if (isSameNode(rNode, newRNode)) {      patchVnode(rNode, newRNode)      rNode = ch[--r]      newRNode = newCh[--newR]      continue    }    if (isSameNode(lNode, newRNode)) {      patchVnode(lNode, newRNode)      api.insertBefore(el, lNode.el, api.nextSibling(rNode.el))      lNode = ch[++l]      newRNode = newCh[--newR]      continue    }    if (isSameNode(rNode, newLNode)) {      patchVnode(rNode, newLNode)      api.insertBefore(el, rNode.el, lNode.el)      rNode = ch[--r]      newLNode = newCh[++newL]      continue    }    // 在vnode未知序列区间[l,r]生成key-idx的map表,用newLNode的key在未知序列中找到可复用的位置    if (!keyIdxMap) keyIdxMap = getKeyIdxMap(ch, l, r) // map    keyIdx = keyIdxMap.get(newLNode.key)    if (!keyIdx) {      api.insertBefore(el, createElement(newLNode), lNode.el)    }    else {      let nodeToMove = ch[keyIdx]      patchVnode(nodeToMove, newLNode)      api.insertBefore(el, nodeToMove.el, lNode.el)    }    newLNode = newCh[++newL]  }}function getKeyIdxMap(ch, l, r) {  let map = new Map()  while (l <= r) map.set(ch[l].key, l++)  return map}

“Vue中Virtual DOM和Diff原理及实现方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Vue中Virtual DOM和Diff原理及实现方法是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Vue中Virtual DOM和Diff原理及实现方法是什么

本篇内容介绍了“Vue中Virtual DOM和Diff原理及实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. vdomvd
2023-07-05

浅析Vue中Virtual DOM和Diff原理及实现

这篇文章主要为大家详细介绍了Vue中Virtual DOM和Diff原理及实现的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
2023-03-21

MD5算法原理及C#和JS实现的方法是什么

本篇内容主要讲解“MD5算法原理及C#和JS实现的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MD5算法原理及C#和JS实现的方法是什么”吧!一、简介MD5 是哈希算法(散列算法)的
2023-07-05

Vue中Watcher和Scheduler的实现原理是什么

这篇文章主要介绍“Vue中Watcher和Scheduler的实现原理是什么”,在日常操作中,相信很多人在Vue中Watcher和Scheduler的实现原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答
2023-06-21

cdn加速原理及实现方法是什么

CDN加速原理是通过在全球分布的节点服务器上缓存静态资源,将用户请求转发至最近的缓存节点,从而提高用户访问速度和稳定性。CDN实现方法包括以下几个步骤:1. 域名解析:将用户请求的域名解析成最优的缓存节点IP地址。2. 负载均衡:根据用户I
2023-05-30

SHA-256算法原理及C#和JS实现的方法是什么

本篇内容主要讲解“SHA-256算法原理及C#和JS实现的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SHA-256算法原理及C#和JS实现的方法是什么”吧!一、简介SHA-256
2023-07-05

C++中内存池的原理及实现方法是什么

这篇文章主要讲解了“C++中内存池的原理及实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++中内存池的原理及实现方法是什么”吧!为什么要用内存池C++程序默认的内存管理(ne
2023-07-05

Java中​HashMap的工作原理及实现方法是什么

今天小编给大家分享一下Java中HashMap的工作原理及实现方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Has
2023-06-03

DES&3DES算法原理及C#和JS实现的方法是什么

这篇文章主要介绍“DES&3DES算法原理及C#和JS实现的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“DES&3DES算法原理及C#和JS实现的方法是什么”文章能帮助大家解决问题。一、
2023-07-05

Java动态代理的原理及实现方法是什么

本篇内容主要讲解“Java动态代理的原理及实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java动态代理的原理及实现方法是什么”吧!代理是指:某些场景下对象会找一个代理对象,来辅助
2023-07-02

在vue中nextTick用法及nextTick的原理是什么

这篇文章主要介绍了在vue中nextTick用法及nextTick的原理是什么,Vue.js是一个流行的前端框架,它提供了一种响应式的数据绑定机制,使得页面的数据与页面的UI组件之间能够自动同步,需要的朋友可以参考下
2023-05-16

PHP单例模式的原理及实现方法是什么

本篇内容介绍了“PHP单例模式的原理及实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!单例模式Singleton Pattern
2023-07-05

python中k-means和k-means++原理是什么及怎么实现

这篇文章主要介绍“python中k-means和k-means++原理是什么及怎么实现”,在日常操作中,相信很多人在python中k-means和k-means++原理是什么及怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作
2023-06-30

CRC校验原理及C语言实现的方法是什么

这篇“CRC校验原理及C语言实现的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“CRC校验原理及C语言实现的方法是
2023-07-05

go原子操作的方式及实现原理是什么

今天小编给大家分享一下go原子操作的方式及实现原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是原子操作?原子操
2023-07-06

JUC中wait与notify方法的实现原理是什么

今天小编给大家分享一下JUC中wait与notify方法的实现原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.O
2023-07-05

C++中线程的原理与实现方法是什么

这篇文章主要介绍“C++中线程的原理与实现方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++中线程的原理与实现方法是什么”文章能帮助大家解决问题。在C++中有多种实现线程的方式C++11
2023-07-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录