Vue 渲染三剑客:createRenderer、h 和 render 详解

article/2025/6/6 1:02:47

目录

一、核心渲染三件套

二、h() 函数:虚拟节点创建器

基本用法

参数详解

虚拟节点(VNode)结构

为什么需要虚拟节点?

三、createRenderer():渲染器工厂

渲染器返回值

自定义渲染器示例

四、render():渲染执行函数

方法签名

工作流程

核心算法伪代码

五、三者的协同工作

完整流程图示

六、实际应用场景

1. 自定义渲染器

1. createElement(type)

2. patchProp(el, key, prev, next)

3. insert(child, parent)

整体执行流程

2. 动态内容更新

七、总结:渲染三剑客的关系


一、核心渲染三件套

在 Vue 的渲染系统中,有三个核心函数构成了渲染的基础:

import { createRenderer, h, render } from 'vue';
  • 1. h() - 虚拟节点创建器
  • 2. createRenderer() - 渲染器工厂
  • 3. render() - 渲染执行函数

这三个函数协同工作,将声明式的组件描述转化为实际的 DOM 操作。下面我们逐一深入解析。

二、h() 函数:虚拟节点创建器

h() 是 Vue 中创建虚拟节点(Virtual DOM Node)的核心函数,名称源自 "hyperscript",意为 "生成 HTML 结构的脚本"

// 创建简单元素
const vnode = h('div', 'Hello World');// 创建带属性的元素
const vnode = h('button', {class: 'btn',onClick: () => console.log('Clicked!')
}, 'Submit');// 创建嵌套结构
const vnode = h('div', [h('h1', 'Main Title'),h('p', 'Content paragraph')
]);

基本用法

// 创建简单元素
const vnode = h('div', 'Hello World');// 创建带属性的元素
const vnode = h('button', {class: 'btn',onClick: () => console.log('Clicked!')
}, 'Submit');// 创建嵌套结构
const vnode = h('div', [h('h1', 'Main Title'),h('p', 'Content paragraph')
]);

参数详解

h() 函数有三种主要调用形式:

// 1. 仅标签类型
h('div')// 2. 标签 + 属性/子元素
h('div', { id: 'app' })
h('div', 'Hello')// 3. 标签 + 属性 + 子元素
h('div', { class: 'container' }, [h('span', 'Item 1'),h('span', 'Item 2')
])

虚拟节点(VNode)结构

h() 返回的虚拟节点对象包含渲染所需的所有信息:

{type: 'div',        // HTML标签或组件对象props: {            // 属性对象id: 'app',class: 'container'},children: [         // 子节点数组{ type: 'p', children: 'Text content' },// ...其他子节点],el: null,           // 对应的真实DOM(渲染后填充)key: undefined,     // 用于优化的key// ...其他内部属性
}

为什么需要虚拟节点?

  1. 跨平台能力:VNode 是平台无关的抽象表示

  2. 高效更新:通过比较新旧 VNode 树,最小化 DOM 操作

  3. 灵活的组件模型:支持函数式组件、异步组件等高级特性

  4. 服务端渲染:可在 Node.js 环境中生成 HTML 字符串

三、createRenderer():渲染器工厂

createRenderer() 是创建自定义渲染器的工厂函数,它接收一个包含平台特定操作的配置对象。

const renderer = createRenderer({// 创建元素createElement(tag) {return document.createElement(tag);},// 设置元素文本setElementText(el, text) {el.textContent = text;},// 插入元素insert(child, parent, anchor = null) {parent.insertBefore(child, anchor);},// 属性比对更新patchProp(el, key, prevValue, nextValue) {// 处理class/style/event/attributes},// 其他操作...
});

渲染器返回值

createRenderer() 返回一个包含关键方法的对象:

const {render,      // 渲染方法hydrate,     // 服务端渲染激活方法createApp    // 创建应用实例
} = renderer;

自定义渲染器示例

实现一个控制台渲染器:

const consoleRenderer = createRenderer({createElement(tag) {return { tag };},insert(child, parent) {console.log(`添加 ${child.tag} 到 ${parent.tag}`);},setElementText(el, text) {console.log(`设置 ${el.tag} 文本: "${text}"`);el.text = text;}
});const vnode = h('div', {}, [h('p', {}, 'Hello Console!')]);
consoleRenderer.render(vnode, { tag: 'root' });

输出:

添加 p 到 div
设置 p 文本: "Hello Console!"
添加 div 到 root

四、render():渲染执行函数

render() 是实际执行渲染工作的方法,它将虚拟 DOM 转换为真实 DOM。

方法签名

function render(vnode: VNode | null, container: HostElement): void;

工作流程

首次渲染

render(h('div', 'Hello'), document.getElementById('app'));
  1. 创建 <div> 元素

  2. 设置文本内容为 "Hello"

  3. 将元素插入到 app 容器中

更新渲染

// 第一次渲染
render(h('div', 'Initial'), container);// 更新内容
render(h('div', 'Updated'), container);
  • 比较新旧 VNode

  • 仅更新变化的文本内容

卸载组件

// 渲染空内容
render(null, container);

核心算法伪代码

function render(vnode, container) {if (vnode === null) {// 卸载逻辑if (container._vnode) {unmount(container._vnode);}} else {// 挂载或更新patch(container._vnode || null, vnode, container);}// 存储当前VNode引用container._vnode = vnode;
}function patch(oldVNode, newVNode, container) {if (oldVNode === null) {// 首次挂载mount(newVNode, container);} else {// 更新逻辑if (shouldUpdate(oldVNode, newVNode)) {// 执行更新updateElement(oldVNode, newVNode);} else {// 完全替换unmount(oldVNode);mount(newVNode, container);}}
}

五、三者的协同工作

理解这三个函数如何协同工作至关重要:

设计阶段

// 1. 创建渲染器(平台相关)
const renderer = createRenderer({ /* DOM操作 */ });// 2. 获取渲染函数
const { render } = renderer;

声明阶段

// 3. 使用h()创建虚拟节点
const vnode = h('div', { class: 'app' }, [h('h1', 'Hello Vue'),h('p', 'This is virtual DOM')
]);

执行阶段

// 4. 使用render()执行渲染
render(vnode, document.getElementById('app'));

完整流程图示

  h() 创建↓
虚拟节点树 (VNode Tree)↓
render() 处理↓
createRenderer 配置↓
真实 DOM 操作↓
浏览器显示

六、实际应用场景

1. 自定义渲染器

1. createElement(type)
  • 作用:创建虚拟 DOM 元素的基础对象

  • 参数

    • type:元素类型(如 'circle'

  • 返回值:返回一个包含 type 属性的基础对象(如 { type: 'circle' }

  • 执行时机:在调用 h() 函数创建虚拟节点时触发

  • 示例

h('circle', ...) // 内部调用 createElement('circle')

 

2. patchProp(el, key, prev, next)
  • 作用:设置/更新虚拟 DOM 元素的属性

  • 参数

    • el:虚拟元素对象(由 createElement 创建)

    • key:属性名(如 'position'

    • prev:旧属性值(首次创建时为 null

    • next:新属性值

  • 执行时机

    • 初始化时:为每个属性设置初始值

    • 更新时:当属性变化时更新值

// 将 position 属性添加到 circle 元素
patchProp(circleObj, 'position', null, [100, 100])
3. insert(child, parent)
  • 作用:将子元素插入父容器,并触发实际绘制

  • 参数

    • child:子虚拟元素(如圆形对象)

    • parent:父容器(此处未直接使用)

  • 执行时机:当虚拟 DOM 的子节点被挂载到父节点时

  • 关键逻辑

if (child.type === 'circle') {draw(child); // 调用绘制函数
}

 

整体执行流程
  1. 创建虚拟 DOM

    const scene = h('canvas', {}, [h('circle', { position: [100, 100], radius: 50, color: 'blue' }),h('circle', { position: [200, 150], radius: 30, color: 'red' })
    ]);
     
  2. 渲染过程

    • 遍历虚拟 DOM 树

    • 对每个 circle 元素:

      1. createElement('circle') → 创建基础对象 { type: 'circle' }

      2. patchProp() → 添加 position/radius/color 属性

      3. insert() → 触发 draw() 绘制

    • draw() → 使用 Canvas API 绘制圆形


    const canvasElement = document.getElementById('canvas');const ctx = canvasElement.getContext('2d');const canvasRenderer = createRenderer({createElement(type) {return { type };},patchProp(el, key, prev, next) {el[key] = next;},insert(child, parent) {if (child.type === 'circle') {draw(child);}},});function draw(element) {const [x, y] = element.position || [0, 0];const radius = element.radius || 10;const color = element.color || 'black';ctx.beginPath();ctx.arc(x, y, radius, 0, Math.PI * 2);ctx.fillStyle = color;ctx.fill();}// 创建Canvas场景const scene = h('canvas', {}, [h('circle', { position: [100, 100], radius: 50, color: 'blue' }),h('circle', { position: [200, 150], radius: 30, color: 'red' })]);canvasRenderer.render(scene, canvasElement);;

2. 动态内容更新

let count = 0;
const container = document.getElementById('app');function update() {// 创建新VNodeconst vnode = h('div', [h('h1', `Count: ${count}`),h('button', { onClick: () => {count++;update(); // 更新视图}}, 'Increment')]);// 渲染更新render(vnode, container);
}// 初始渲染
update();

七、总结:渲染三剑客的关系

函数角色输入输出
h()声明式构建界面组件描述虚拟节点(VNode)
createRenderer()创建特定平台的渲染能力平台DOM操作实现渲染器对象
render()执行渲染过程VNode + DOM容器实际UI更新

关键理解要点

  1. h() 是声明式的:描述"应该是什么样子"

  2. createRenderer() 是平台适配层:决定"如何实现渲染"

  3. render() 是执行引擎:处理"何时以及怎样更新"

这种分层架构使得 Vue 能够:

  • 保持核心逻辑与平台无关

  • 轻松实现跨平台渲染

  • 提供高效的更新机制

  • 保持开发者友好的声明式 API

理解这三个核心函数的工作原理,是深入掌握 Vue 渲染机制和实现自定义渲染解决方案的关键基础。


http://www.hkcw.cn/article/xdcRIQMJnu.shtml

相关文章

Unity-UI组件详解

今天我们来学习Unity的UI的详解&#xff0c;这部分的内容相对较少&#xff0c;对于程序员来说主要的工作是负责将各种格式的图片呈现在显示器上并允许操作这些图片。 本篇帖子的理论依据依然是官方开源的UGUI代码&#xff0c;网址为&#xff1a;GitHub - Unity-Technologies/u…

化工厂爆炸事件看制造业AI转型

一、事件警示&#xff1a;化工制造安全风险不容忽视 近日&#xff0c;某化学有限公司发生事故。涉事工厂主体工程建设有2座硝化装置区&#xff0c;1座加氢装置区&#xff0c;均属于危险工艺生产装置。硝化反应通常属于强放热反应&#xff0c;原料及产物具有爆炸危险性&#xf…

Ubuntu系统安装与配置NTP时间同步服务

Ubuntu系统安装与配置NTP时间同步服务 一、NTP服务介绍NTP服务简介工作原理系统环境准备检查当前时间状态二、方案选择:systemd-timesyncd vs ntpd三、使用systemd-timesyncd时间同步1. 方案介绍2. 配置优化3. 应用配置4. 验证状态5. 检查当前时间状态6. 查看当前实践四、使用…

【小红书】API接口,获取笔记核心数据

小红书笔记核心数据API接口详解 - 深圳小于科技提供专业数据服务 深圳小于科技&#xff08;官网&#xff1a;https://www.szlessthan.com&#xff09;推出的小红书笔记核心数据API接口&#xff0c;为开发者提供精准的笔记互动数据分析能力&#xff0c;助力内容运营与商业决策。…

ElasticStack技术之logstash介绍

一、什么是Logstash Logstash 是 Elastic Stack&#xff08;ELK Stack&#xff09;中的一个开源数据处理管道工具&#xff0c;主要用于收集、解析、过滤和传输数据。它支持多种输入源&#xff0c;如文件、网络、数据库等&#xff0c;能够灵活地对数据进行处理&#xff0c;比如…

InternLM2/LM2.5/ViT/VL1.5/VL2.0笔记: 核心点解析

00 前言 本文主要是记录一下关于多模态大模型InternLM/InternVL系列的一些要点的理解。还是那句话&#xff0c;好记性&#xff0c;不如烂笔头。本文当成个人笔记用&#xff0c;行文风格和先前写的LLaVA系列一致。本文的重点是讲解多模态模型InternVL 1.5&#xff0c;但是Intern…

帝可得 - 设备管理

一. 需求说明 设备管理主要涉及到三个功能模块&#xff0c;业务流程如下&#xff1a; 新增设备类型: 允许管理员定义新的售货机型号&#xff0c;包括其规格和容量。 新增设备: 在新的设备类型定义后&#xff0c;系统应允许添加新的售货机实例&#xff0c;并将它们分配到特定的…

建设指南 | Cloud Apps + AI Apps端到端智能应用开发平台

在“云AI”作为基础设施的时代&#xff0c;研发、运维、信息化等部门&#xff0c;通常会面临的棘手问题都有哪些&#xff1a; 算力资源难以统一调度和管理&#xff1b;AI算法研发环境搭建复杂&#xff1b;不同模型部署方式繁杂&#xff0c;统一监控难&#xff1b;AI应用开发效…

【灵动Mini-F5265-OB】vscode+gcc工程创建、下载、调试

【前言】 【灵动Mini-F5265-OB】在官方的例程中提供了mdk、IAR的开发环境&#xff0c;使用起来非常方便。有位大佬也提供了一个gcc的示例&#xff0c;但是我使用vscode的keil插件进行工程创建&#xff0c;但是提示pack是对不上的。所以我决定重新创建我的vscode来创建开发环境。…

【AI论文】VF-Eval:评估多模态大型语言模型(MLLM)在生成人工智能生成内容(AIGC)视频反馈方面的能力

摘要&#xff1a;多模态大型语言模型&#xff08;MLLMs&#xff09;最近在视频问答领域得到了广泛研究。然而&#xff0c;现有的大多数评估都侧重于自然视频&#xff0c;而忽视了合成视频&#xff0c;例如人工智能生成的内容&#xff08;AIGC&#xff09;。与此同时&#xff0c…

Docker 镜像(或 Docker 容器)中查找文件命令

在 Docker 镜像&#xff08;或 Docker 容器&#xff09;中运行如下两个命令时&#xff1a; cd / find . -name generate.py它们的含义如下&#xff0c;我们来一行一行详细拆解&#xff0c;并结合例子讲解&#xff1a; ✅ 第一行&#xff1a;cd / ✅ 含义 cd 是“change dire…

DiskGenius专业版v6.0.1.1645:分区管理、数据恢复、备份还原,一应俱全!

各位小伙伴&#xff0c;大家好&#xff01;今天阿灿给大家带来一款超好用的分区工具&#xff0c;DiskGenius专业版。这款工具堪称电脑管理界的“瑞士军刀”&#xff0c;功能强大&#xff0c;现在出了新版本v6.0.1.1645&#xff0c;简繁中文单文件便携版&#xff0c;使用超方便。…

‌CDGP|数据治理的低效性:企业AI落地的另一大挑战

在数字化转型的浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;已成为推动企业创新发展的重要力量。然而&#xff0c;尽管AI技术具有巨大的潜力和优势&#xff0c;但许多企业在尝试落地AI项目时却面临着重重挑战。其中&#xff0c;数据治理的低效性尤为突出&#xff0c;…

linux学习第19、20天(父子进程)

ps ajx -->查看pid&#xff0c;ppid&#xff0c;gid&#xff0c;sid 父子进程 父子进程相同&#xff1a; 刚fork后&#xff0c;data段、text段、堆&#xff0c;栈、环境变量、全局变量、进程工作目录位置、信号处理方式 父子进程不同&#xff1a; 进程id、返回值、各自的…

AI写作革命:重塑创作未来

人工智能写作技术&#xff1a;革新创作方式的智能利器 人工智能写作技术&#xff08;AI写作技术&#xff09;是指利用自然语言处理&#xff08;NLP&#xff09;、机器学习&#xff08;ML&#xff09;等人工智能技术&#xff0c;辅助或自动化完成文本的创作、编辑与优化。这一技…

法律大语言模型(Legal LLM)技术架构

目录 摘要 1 法律AI大模型技术架构 1.1 核心架构分层 1.2 法律知识增强机制 2 关键技术突破与对比 2.1 法律专用组件创新 2.2 性能对比(合同审查场景) 3 开发部署实战指南 3.1 环境搭建流程 3.2 合同审查代码示例 4 行业应用与挑战 4.1 典型场景效能提升 4.2 关…

深入理解 C# Razor Pages:构建现代 Web 应用的利器

在现代 Web 开发中&#xff0c;选择合适的框架至关重要。ASP.NET Core 提供了多种开发模式&#xff0c;其中 Razor Pages 因其简单性、高效性和易用性&#xff0c;成为构建页面导向 Web 应用的首选方案。相比于传统的 MVC&#xff08;Model-View-Controller&#xff09;模式&am…

AgenticSeek 本地部署教程(Windows 系统)

#工作记录 Fosowl/agenticSeek&#xff1a;完全本地的 Manus AI。 部署排错参考资料在文末 或查找往期笔记。 AgenticSeek 本地部署教程&#xff08;Windows 系统&#xff09; 一、环境准备 1. 安装必备工具 Docker Desktop 下载地址&#xff1a;Docker Desktop 官网 安装后启…

后台管理系统八股

项⽬地址&#xff1a;https://github.com/Xiaodie-888/Frontend.git 前端 https://github.com/Xiaodie-888/backend.git 后端 技术栈&#xff1a;Vue3ViteTyprscriptPiniaElement-plusVue-RouterExpress.jsMySQL 核⼼⼯作与技术&#xff1a; 基础组件封装&#xff1a;基于 Ele…

014校园管理系统技术解析:构建智慧校园管理平台

校园管理系统技术解析&#xff1a;构建智慧校园管理平台 在教育信息化快速发展的当下&#xff0c;校园管理系统成为提升学校管理效率、优化校园服务的重要工具。该系统集成院校管理、投票管理等多个核心模块&#xff0c;面向管理员、用户和院内管理员三种角色&#xff0c;通过…