当前位置: 首页 > news >正文

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

目录

一、核心渲染三件套

二、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 渲染机制和实现自定义渲染解决方案的关键基础。

相关文章:

  • 工厂方法模式深度解析:从原理到应用实战
  • 使用ArcPy生成地图系列
  • win11中使用grep
  • 国产高性能pSRAM选型指南:CSS6404LS-LI 64Mb QSPI伪静态存储器
  • 【Visual Studio 2022】卸载安装,ASP.NET
  • VS下C++及C#项目打包发布方法
  • Cursor + Claude 4:微信小程序流量主变现开发实战案例
  • C++ 中的依赖注入(Dependency Injection)
  • 【论文阅读】Dolphin: Document Image Parsing via Heterogeneous Anchor Prompting
  • 菲尔斯特非接触测温技术的核心应用与选型指南
  • 网络安全问题及对策研究
  • 5分钟申请edu邮箱【方案本周有效】
  • Linux 与 Windows:哪个操作系统适合你?
  • 用 Vue 做一个轻量离线的“待办清单 + 情绪打卡”小工具
  • 计算A图片所有颜色占B图片红色区域的百分比
  • 简简单单探讨下starter
  • 手动移植UGUI
  • 网络原理1
  • Baklib内容中台AI重构智能服务
  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(31):そう
  • 全网营销实战培训/seo网络营销的技术
  • app电商网站/速推网
  • 受欢迎的网站建设平台/谷歌搜索引擎怎么才能用
  • 深圳出台多个利好政策/seo工具软件
  • win7 iis配置网站 视频教程/爱站网能不能挖掘关键词
  • 在putty做网站要拷贝什么/2345浏览器网址导航