【vue】什么是虚拟Dom,怎么实现虚拟DOM,虚拟DOM一定更快吗

2024-02-28 14:44

本文主要是介绍【vue】什么是虚拟Dom,怎么实现虚拟DOM,虚拟DOM一定更快吗,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是虚拟Dom

虚拟 DOM 基于虚拟节点 VNode,VNode 本质上是一个对象,VDOM 就是VNode 组成的

        废话,js 中所有的东西都是对象

虚拟DOM 为什么快,做了哪些优化

  1. 批量更新
    1. 多个DOM合并更新
    2. 减少浏览器的重排和重绘
  2. 局部更新
    1. 通过新VDOM对比,diff 算法
    2. 只更新需要重新渲染的真实 DOM
    3. 减少开销
  3. 跨平台支持
    1. node、浏览器、移动端、小程序都可以支持

虚拟DOM一定更快吗,不一定

  1. 额外的内存占用
    1. 虚拟DOM需要维护一个表示整个组件树的数据结构,这可能会占用额外的内存。
  2. VDOM 生成、对比,渲染都有额外的开销
  3. VDOM 适合中大型项目
  4. 简单的程序不适合VDOM,直接操作真实DOM更好
  5. 有些框架不用VDOM也很快
    1. 使用异步渲染技术
      1. requestAnimationFrame
      2. MutationObserver

实现VDOM

vue3 源码 runtime-core/src/vnode.ts 有关于 VNode 的定义

export interface VNode<HostNode = RendererNode,HostElement = RendererElement,ExtraProps = { [key: string]: any },
> {/*** @internal*/__v_isVNode: true/*** @internal*/[ReactiveFlags.SKIP]: truetype: VNodeTypesprops: (VNodeProps & ExtraProps) | nullkey: string | number | symbol | nullref: VNodeNormalizedRef | null/*** SFC only. This is assigned on vnode creation using currentScopeId* which is set alongside currentRenderingInstance.*/scopeId: string | null/*** SFC only. This is assigned to:* - Slot fragment vnodes with :slotted SFC styles.* - Component vnodes (during patch/hydration) so that its root node can*   inherit the component's slotScopeIds* @internal*/slotScopeIds: string[] | nullchildren: VNodeNormalizedChildrencomponent: ComponentInternalInstance | nulldirs: DirectiveBinding[] | nulltransition: TransitionHooks<HostElement> | null// DOMel: HostNode | nullanchor: HostNode | null // fragment anchortarget: HostElement | null // teleport targettargetAnchor: HostNode | null // teleport target anchor/*** number of elements contained in a static vnode* @internal*/staticCount: number// suspensesuspense: SuspenseBoundary | null/*** @internal*/ssContent: VNode | null/*** @internal*/ssFallback: VNode | null// optimization onlyshapeFlag: numberpatchFlag: number/*** @internal*/dynamicProps: string[] | null/*** @internal*/dynamicChildren: VNode[] | null// application root node onlyappContext: AppContext | null/*** @internal lexical scope owner instance*/ctx: ComponentInternalInstance | null/*** @internal attached by v-memo*/memo?: any[]/*** @internal __COMPAT__ only*/isCompatRoot?: true/*** @internal custom element interception hook*/ce?: (instance: ComponentInternalInstance) => void
}

使用 createVNode 创建虚拟节点  

虚拟 dom 就是虚拟 node 节点的结合,每个 Vnode 都有一个 children 属性,children 的每个元素也是一个 VNode,他们有共同的根节点,就形成了一个虚拟的树结构。

自己实现虚拟 DOM 的重点步骤

  1. 定义一个 VNode 数据结构【这个如果是用 js,没有接口类型定义,就不用在代码中直接体现】
    1. 类中有 children 属性【用来存储子节点】
    2. 有 tag 代表标签【用来存储真实 html 的标签, div, p, span 等】
    3. 有 props 节点的属性【用来存储 html 元素的各种属性,style, class 等】
  2. 定义一个创建 VNode 的函数或类【createVNode】
  3. 定义一个渲染函数,将 VDOM 转成真实节点【render】

下面是我根据上面的步骤自己实现的:

// 创建虚拟节点函数
function createVNode(tag, props, children) {// 虚拟节点必须包含的三个属性return {isVnode: true, // 用来判断是否是虚拟节点,也不可不用这个tag,props,children // 数组}
}function render(VNode) {const { tag, props, children } = VNode// 创建真实 Dom 元素const element = document.createElement(tag)// 给 dom 元素增加属性for(let key in props) {element.setAttribute(key, props[key])}for(let i =0; i < children.length; i ++) {let child = children[i]// 如果子节点还是虚拟节点,就递归调用渲染函数if (child.isVnode ) {element.appendChild(render(child))} else {// 最终的真实节点element.appendChild(document.createTextNode(child))}}return element
}const vDom = createVNode('div', {style: 'color:red'}, [createVNode('h1', { style: 'color:blue'}, ['你好']),createVNode('p', {}, ['再见'])
])const realDom = render(vDom)
console.log(realDom)

 复制上面代码到浏览器开发者工具中可以直接运行

下面 chatgpt 给的答案,使用了一个 vnode类,看起来更好一些:

// 定义虚拟DOM节点的数据结构
class VNode {constructor(tag, props, children) {this.tag = tag;this.props = props;this.children = children;}// 渲染虚拟DOM为真实DOMrender() {const element = document.createElement(this.tag);// 设置属性for (const key in this.props) {element.setAttribute(key, this.props[key]);}// 渲染子节点this.children.forEach(child => {if (child instanceof VNode) {element.appendChild(child.render());} else {element.appendChild(document.createTextNode(child));}});return element;}
}// 创建虚拟DOM
const virtualDOM = new VNode('div', { class: 'container' }, [new VNode('h1', {}, ['Hello, Virtual DOM!']),new VNode('p', {}, ['This is a paragraph.']),
]);// 将虚拟DOM渲染到页面中
const root = document.getElementById('root');
root.appendChild(virtualDOM.render());

这篇关于【vue】什么是虚拟Dom,怎么实现虚拟DOM,虚拟DOM一定更快吗的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/755799

相关文章

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机