feat(stages): 添加性能测试和虚拟DOM实现阶段

添加stage04-perf用于真实DOM操作性能对比,包含三个不同的更新策略:
- innerHTML全量更新
- createElement全量重建
- 精确单节点更新

添加stage04用于模拟异步接口数据获取后的渲染演示

添加stage05实现虚拟DOM基础功能,提供VNode对象描述DOM树结构和递
归渲染函数
This commit is contained in:
zzy
2026-05-02 12:36:53 +08:00
parent fc87cf4622
commit 845789cd60
7 changed files with 483 additions and 0 deletions

12
stage05/index.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang='zh-cn'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<title>Stage 05: 虚拟 DOM 初体验</title>
</head>
<body>
<div id="minivue"></div>
<script src="./index.js"></script>
</body>
</html>

73
stage05/index.js Normal file
View File

@@ -0,0 +1,73 @@
/**
* Stage 05虚拟 DOM 初体验
* 用纯 JavaScript 对象描述 DOM 树,并编写递归渲染函数
*/
/**
* @typedef {Object} VNode
* @property {string} type - 元素标签或 'text'
* @property {Object<string, string>} [props] - 属性
* @property {(VNode|string)[]} [children] - 子节点
* @property {string} [value] - 文本内容(仅 type='text' 时使用)
*/
/**
* 渲染 VNode 树为真实 DOM 并挂载到容器
* @param {VNode} vnode
* @param {HTMLElement} container
* @returns {HTMLElement | Text} 挂载的真实 DOM
*/
function render(vnode, container) {
let el;
if (vnode.type === "text") {
el = document.createTextNode(vnode.value);
} else {
el = document.createElement(vnode.type);
// 设置属性
if (vnode.props) {
for (const key in vnode.props) {
el.setAttribute(key, vnode.props[key]);
}
}
// 递归渲染子节点
if (vnode.children) {
vnode.children.forEach((child) => {
// 子节点可能是字符串 (自动转为文本 VNode)
if (typeof child === "string") {
render({ type: "text", value: child }, el);
} else {
render(child, el);
}
});
}
}
container.appendChild(el);
return el;
}
/**
* 手动构建一个卡片 VNode
* @type {VNode}
*/
const userNode = {
type: "div",
props: { class: "user-card" },
children: [
{
type: "h2",
children: [{ type: "text", value: "姓名: 小明" }],
},
{
type: "p",
children: [{ type: "text", value: "年龄: 18" }],
},
{
type: "span",
children: [{ type: "text", value: "学生" }],
},
],
};
const root = document.getElementById("minivue");
render(userNode, root);