feat(minivue): 添加stage06 h函数创建VNode功能并完善文档
- 在README.md中添加了所有阶段的说明,包括stage00到stage09的内容 - 移除了stage05中render函数的返回值和注释,简化函数实现 - 新增stage06/index.html基础页面结构 - 实现stage06 h函数自动创建VNode功能,支持: - 类型定义VNode和VNodeChild - h函数创建虚拟节点,支持嵌套子节点 - mount函数递归挂载VNode到真实DOM - 属性设置和文本节点处理 - 提供了完整的使用示例,展示用户卡片组件的渲染
This commit is contained in:
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
- stage00 纯html
|
||||||
|
- stage01 命令式 DOM
|
||||||
|
- stage02 声明式渲染
|
||||||
|
- stage03 列表渲染
|
||||||
|
- stage04 模拟异步接口
|
||||||
|
- stage05 虚拟 DOM 初体验
|
||||||
|
- stage06 用 h 函数自动创建 VNode
|
||||||
|
- stage07 重新渲染暴露全量更新问题
|
||||||
|
- stage08 简单 patch(无 key 对比)
|
||||||
|
- stage09 带 key 的 diff 算法
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
* 渲染 VNode 树为真实 DOM 并挂载到容器
|
* 渲染 VNode 树为真实 DOM 并挂载到容器
|
||||||
* @param {VNode} vnode
|
* @param {VNode} vnode
|
||||||
* @param {HTMLElement} container
|
* @param {HTMLElement} container
|
||||||
* @returns {HTMLElement | Text} 挂载的真实 DOM
|
|
||||||
*/
|
*/
|
||||||
function render(vnode, container) {
|
function render(vnode, container) {
|
||||||
let el;
|
let el;
|
||||||
@@ -43,7 +42,6 @@ function render(vnode, container) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.appendChild(el);
|
container.appendChild(el);
|
||||||
return el;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
12
stage06/index.html
Normal file
12
stage06/index.html
Normal 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 06: 用 h 函数自动创建 VNode</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="minivue"></div>
|
||||||
|
<script src="./index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
70
stage06/index.js
Normal file
70
stage06/index.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Stage 06:用 h 函数自动创建 VNode
|
||||||
|
* 从“手动拼对象”到“用函数生成”,与 Vue 的 createElement 原理一致
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {string|number|VNode} VNodeChild
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} VNode
|
||||||
|
* @property {string} type
|
||||||
|
* @property {Object<string, any>} [props]
|
||||||
|
* @property {VNodeChild[]} [children]
|
||||||
|
* @property {HTMLElement | null} [el]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建虚拟节点(VNode)
|
||||||
|
* @param {string} type - 标签名,如 'div'
|
||||||
|
* @param {Object<string, any> | null} props - 属性或 null
|
||||||
|
* @param {...(string|VNode)} children - 子节点,字符串会自动转为文本节点
|
||||||
|
* @returns {VNode}
|
||||||
|
*/
|
||||||
|
function h(type, props, ...children) {
|
||||||
|
const normalizedChildren = children.flat(Infinity);
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
props: props || {},
|
||||||
|
children: normalizedChildren,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 VNode 挂载到真实 DOM(递归)
|
||||||
|
* @param {VNode} vnode
|
||||||
|
* @param {HTMLElement} container
|
||||||
|
*/
|
||||||
|
function mount(vnode, container) {
|
||||||
|
const 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) => {
|
||||||
|
if (typeof child === "string" || typeof child === "number") {
|
||||||
|
el.appendChild(document.createTextNode(String(child)));
|
||||||
|
} else {
|
||||||
|
mount(child, el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
container.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = document.getElementById("minivue");
|
||||||
|
const vnode = h(
|
||||||
|
"div",
|
||||||
|
{ class: "user-card" },
|
||||||
|
h("h2", null, "姓名: 小明"),
|
||||||
|
h("p", null, "年龄: 18"),
|
||||||
|
h("span", null, "学生"),
|
||||||
|
);
|
||||||
|
|
||||||
|
mount(vnode, root);
|
||||||
Reference in New Issue
Block a user