Vue3中虚拟dom转成真实dom的过程详解

 更新时间:2024年09月10日 08:24:55   作者:zykk  
Vue.js 在其运行过程中会将模板编译成虚拟 DOM (VNode),然后再将 VNode 渲染成实际的 DOM 节点,这个过程是由 Vue 内部的编译器和渲染系统完成的,本文给大家介绍了Vue3中虚拟dom转成真实dom的过程,需要的朋友可以参考下

前言

Vue.js 在其运行过程中会将模板编译成虚拟 DOM (VNode),然后再将 VNode 渲染成实际的 DOM 节点。这个过程是由 Vue 内部的编译器和渲染系统完成的.

虽然Vue 3 的虚拟 DOM 编译过程对于开发者来说通常是透明的,但了解这些内部机制有助于更好地理解和优化应用程序。

如果你对 Vue 3 的内部实现感兴趣,可以查阅 Vue 3 的官方文档或阅读 Vue 3 的源码来深入了解这一过程。

Vue 3 中虚拟 DOM 的编译过程

1. 模板编译

在 Vue 3 中,模板编译主要由两个阶段组成:解析和优化。

  • 解析阶段:Vue 3 的编译器会将模板字符串解析成一个抽象语法树 (Abstract Syntax Tree, AST),这个树结构表示了模板的结构和内容。编译器会识别出模板中的各种指令(如 v-if, v-for, v-bind 等)并将它们转换成对应的 AST 节点。
  • 优化阶段:编译器会对 AST 进行优化,以减少不必要的计算和 DOM 操作。例如,它可以提前计算静态节点,并将其标记为静态的,这样在渲染时就不需要重新生成这些节点。

2. 生成渲染函数

一旦 AST 被创建并优化后,编译器会生成一个渲染函数,这个函数可以用来创建虚拟 DOM 节点(VNode)。渲染函数通常会利用 Vue 内置的 h 函数(createVNode 的别名)来创建 VNode。

3. 创建虚拟 DOM (VNode)

在 Vue 3 中,h 函数被用来创建 VNode。一个 VNode 是一个 JavaScript 对象,它包含了关于 DOM 节点的信息,如标签名、属性、子节点等。例如:

const vnode = h(
  'div', // 标签名
  { id: 'app' }, // 属性对象
  'Hello Vue 3!' // 子节点
);

4. 渲染到真实 DOM

当 VNode 被创建后,Vue 会使用高效的算法来比较新旧 VNode,并更新真实的 DOM。这个过程称为 patching。Vue 3 的 diff 算法旨在最小化 DOM 操作,从而提高性能。

今天来简单介绍一下如何将一份虚拟dom转成真实dom。

vdomToDom

虚拟dom结构已有,挂载到root节点上,请问如何实现render函数?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="root"></div>


    <script>
        const vnode = {
            tag: 'div',
            attrs: {
                id: 'app',
                class:'box'
            },
            children: [
                {
                    tag: 'span',
                    children: [{
                        tag: 'a',
                        children: [],
                    }],
                },
                {
                    tag: 'span',
                    children: [{
                        tag: 'a',
                        children: [],
                    }]
                }
            ]
        }


        render(vnode,document.getElementById('root'))

        function render(vnode, container) {
            
        }
    </script>
</body>

</html>

我们先来看一眼这份虚拟dom长什么样。

首先最外层有个id为app类名为box的div,里面有两个子节点span,第一个子节点中又有一个a,第二个子节点中也有一个a

那么vue中编译dom的原理是什么,我们来一份简易版看看。

首先我们就想有一个方法只要给一个虚拟dom就能生成dom,然后将其挂载到root上去,接下来就是如何实现createDom

function render(vnode, container) {
            const newDom = createDom(vnode)
            container.appendChild(newDom)
        }
function createDom(vnode) {
            const { tag, attrs, children } = vnode
            const dom = document.createElement(tag)
            if (typeof attrs === 'object' && attrs !== null) {
                updateProps(dom, {}, attrs) // 为dom添加属性
            }
            if (children.length > 0) {
                reconcileChildren(children, dom) // 为dom添加子容器
            }
            return dom
        }

然后思考,如何为子容器添加属性以及如何为容器添加子容器?

function updateProps(dom, oldProps = {}, newProps = {}) {
            for (const key in newProps) {
                if (key === 'style') {
                    let styleObj = newProps[key]
                    for (let attr in styleObj) {
                        dom.style[attr] = styleObj[attr]
                    }
                } else { // id / class
                    dom[key] = newProps[key]
                }
            }
        }

        function reconcileChildren(children, dom) {
            for (let child of children) {
                render(child, dom)
            }
        }

完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="root"></div>


    <script>
        const vnode = {
            tag: 'div',
            attrs: {
                id: 'app',
                className: 'box'
            },
            children: [
                {
                    tag: 'span',
                    children: [{
                        tag: 'a',
                        children: [],
                    }],
                },
                {
                    tag: 'span',
                    children: [{
                        tag: 'a',
                        children: [],
                    }]
                }
            ]
        }


        render(vnode, document.getElementById('root'))

        function render(vnode, container) {
            const newDom = createDom(vnode)
            container.appendChild(newDom)
        }

        function createDom(vnode) {
            const { tag, attrs, children } = vnode
            const dom = document.createElement(tag)
            if (typeof attrs === 'object' && attrs !== null) {
                updateProps(dom, {}, attrs) // 为dom添加属性
            }
            if (children.length > 0) {
                reconcileChildren(children, dom) // 为dom添加子容器
            }
            return dom
        }
        function updateProps(dom, oldProps = {}, newProps = {}) {
            for (const key in newProps) {
                if (key === 'style') {
                    let styleObj = newProps[key]
                    for (let attr in styleObj) {
                        dom.style[attr] = styleObj[attr]
                    }
                } else { // id / class
                    dom[key] = newProps[key]
                }
            }
        }

        function reconcileChildren(children, dom) {
            for (let child of children) {
                render(child, dom)
            }
        }
    </script>
</body>

</html>

效果

以上就是Vue3中虚拟dom转成真实dom的过程详解的详细内容,更多关于Vue3 虚拟dom转成真实dom的资料请关注脚本之家其它相关文章!

相关文章

  • Vue中通过属性绑定为元素绑定style行内样式的实例代码

    Vue中通过属性绑定为元素绑定style行内样式的实例代码

    这篇文章主要介绍了Vue中通过属性绑定为元素绑定style行内样式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • 基于vue实现swipe分页组件实例

    基于vue实现swipe分页组件实例

    本篇文章主要介绍了基于vue实现swipe分页组件实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • vue+springmvc导出excel数据的实现代码

    vue+springmvc导出excel数据的实现代码

    这篇文章主要介绍了vue+springmvc导出excel数据的实现代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • vue中table表头单元格合并(附单行、多级表头代码)

    vue中table表头单元格合并(附单行、多级表头代码)

    本文主要介绍了vue中table表头单元格合并(附单行、多级表头代码),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Vue3环境安装以及项目搭建全过程

    Vue3环境安装以及项目搭建全过程

    Vue工程化项目环境配置还是比较麻烦的,下面这篇文章主要给大家介绍了关于Vue3环境安装以及项目搭建的相关资料,文中通过图文以及代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • vue实现页面缓存功能

    vue实现页面缓存功能

    这篇文章主要为大家详细介绍了vue实现页面缓存功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • vue 组件间的通信之子组件向父组件传值的方式

    vue 组件间的通信之子组件向父组件传值的方式

    这篇文章主要介绍了vue 组件间的通信之子组件向父组件传值的方式总结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 如何用vue3+Element plus实现一个完整登录功能

    如何用vue3+Element plus实现一个完整登录功能

    要实现用户的登录功能,可以使用Vue3和Element Plus,下面这篇文章主要给大家介绍了关于如何基于Vue3和Element Plus组件库实现一个完整的登录功能,文中提供了详细的代码示例,需要的朋友可以参考下
    2023-10-10
  • Vue.js的兄弟组件传值实现组件间互动

    Vue.js的兄弟组件传值实现组件间互动

    在Vue.js中,组件是构建用户界面的基本单位,而兄弟组件传值是组件间交互的重要组成部分,本文将探讨兄弟组件传值的方法和优势,并通过有趣的示例展示其强大的功能,需要的朋友可以参考下
    2025-03-03
  • vue 组件开发原理与实现方法详解

    vue 组件开发原理与实现方法详解

    这篇文章主要介绍了vue 组件开发原理与实现方法,结合实例形式详细分析了vue.js组件开发的原理与实现方法,需要的朋友可以参考下
    2019-11-11

最新评论