Vue3源码解析之 runtime

本文为原创文章,未获授权禁止转载,侵权必究!

本篇是 Vue3 源码解析系列第 6 篇,关注专栏

前言

当设计一个框架时,我们通常会选择 纯运行时纯编译时运行时 + 编译时 这三种。这里我们来聊聊 Vue3 源码中的 runtime 运行时,主要在 packages/runtime-core 目录下,核心提供了 hrender 等函数。在讲解它们之前,我们需了解下 HTML DOM 树虚拟 DOM 等概念。

HTML DOM 树

通过节点构成的一个树形结构,我们称为 HTML DOM 节点树。在 这篇文章 中做了详细的解释,这里就不再展开讲解,我们通过一个例子来一探究竟:

html 复制代码
<div> 
    <h1>hello h1</h1> 
    <!-- 这里是注释 --> 
    hello div 
</div>

浏览器看到上述代码时,它会生成一个对应的 DOM 树 来展示:

可以看出浏览器在运行代码时,无论是 标签文本注释 等都会生成对应的节点,这也就构成了 HTML DOM 树。

虚拟 DOM

什么是 虚拟 DOMVue 文档 中也做了相应的解释,大家可以点击进行查看,大致我们可以理解为:

虚拟 DOM 是一种编程概念,意为将目标所需的 UI 通过数据结构 "虚拟" 地表示出来,保存在内存中,然后将真实的 DOM 与之保持同步。这个概念有 React 率先开拓,随后在许多不同的框架中都有不同的实现,当然也包括 Vue。

我们还是通过一个例子来说明下:

js 复制代码
// 真实 DOM 
<div>text</div>

// 虚拟 DOM 表示
const vnode = {
    type: 'div', // 父节点类型 div
    children: 'text' // 子节点内容 text
}

// 真实 DOM
<div>
    <h1>hello h1</h1>
    <!-- TODO: comment -->
    hello div
</div>

// 虚拟 DOM 表示 
const vnode = {
    type: 'div', // 父节点类型 div
    children: [ // 多个子节点
        {
            type: 'h1', // 子节点类型 h1
            children: 'hello h1' // 子节点内容 hello h1       
        },
        {
            type: Comment, // 子节点类型 Comment
            children: 'TODO: comment' // 子节点内容 TODO: comment       
        },
        'hello div'   // 子节点内容 hello div
    ]
}

可以看出 虚拟 DOM 类似把真实 DOM 转换成一个 VNode 对象,该 对象 存在节点的类型 type,子节点信息 children 等属性,而子节点有可能是 字符串,也可能是包含其他子节点的 数组

而在 runtime 运行时,渲染器 renderer 会遍历整个 虚拟 DOM 树,并据此构建 真实的 DOM 树,这个过程我们把它叫做挂载 mount

当这个 VNode 对象发生变化时,那么我们会对比 旧的 VNode新的 VNode 之间的区别,找出它们之间的区别,并应用这其中的变化到真实的 DOM 上,这个过程被称为 更新 patch

Vue 中转换为 VNode 对象就是通过 h 函数来完成的,我们通过调试来看下 h 函数的返回值:

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../../../dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script>
      const { h } = Vue

      const vnode = h(
        'div',
        {
          class: 'test'
        },
        'hello render'
      )

      console.log(vnode)
    </script>
  </body>
</html>
js 复制代码
// vnode
{ 
    // 是否是一个 VNode 对象 
    "__v_isVNode": true, 
    // 当前节点类型 
    "type": "div", 
    // 当前节点属性 
    "props": { "class": "text" }, 
    // 子节点 
    "children": "hello render"
}

h 函数定义在 packages/runtime-core/src/h.ts 文件中,它接收三个参数:

  1. type: string | Component 既可以是一个字符串(用于原生元素)也可以是一个 Vue 组件定义
  2. props?: object | null 要传递的 prop
  3. children?: Children | Slot | Slots 子节点

最终 VNode 对象通过 render 函数渲染为真实 DOM,该 render 函数定义在 packages/runtime-core/src/renderer.ts 文件中,实际执行的是 createRenderer 方法,它接收两个参数:

  1. vnode 虚拟节点树 或者叫做虚拟 DOM 树
  2. container 承载的容器,真实节点渲染的位置

总结

  1. 理解 HTML DOM 树 和 虚拟 DOM 的区别。
  2. 虚拟 DOM 实际是一个 VNode 对象,包含节点类型、属性等信息。
  3. Vue3runtime 运行时,主要通过 h 函数转换成 VNode 对象,再通过 render 函数渲染成真实 DOM 。

Vue3 源码实现

vue-next-mini

Vue3 源码解析系列

  1. Vue3源码解析之 源码调试
  2. Vue3源码解析之 reactive
  3. Vue3源码解析之 ref
  4. Vue3源码解析之 computed
  5. Vue3源码解析之 watch
  6. Vue3源码解析之 runtime
  7. Vue3源码解析之 h
相关推荐
以对_8 分钟前
uview表单校验不生效问题
前端·uni-app
程序猿小D1 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa
奔跑吧邓邓子2 小时前
npm包管理深度探索:从基础到进阶全面教程!
前端·npm·node.js
前端李易安2 小时前
ajax的原理,使用场景以及如何实现
前端·ajax·okhttp
汪子熙2 小时前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
杨荧2 小时前
【JAVA开源】基于Vue和SpringBoot的旅游管理系统
java·vue.js·spring boot·spring cloud·开源·旅游
Envyᥫᩣ3 小时前
《ASP.NET Web Forms 实现视频点赞功能的完整示例》
前端·asp.net·音视频·视频点赞
Мартин.7 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
一 乐8 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
昨天;明天。今天。8 小时前
案例-表白墙简单实现
前端·javascript·css