feat(stages): 添加性能测试和虚拟DOM实现阶段
添加stage04-perf用于真实DOM操作性能对比,包含三个不同的更新策略: - innerHTML全量更新 - createElement全量重建 - 精确单节点更新 添加stage04用于模拟异步接口数据获取后的渲染演示 添加stage05实现虚拟DOM基础功能,提供VNode对象描述DOM树结构和递 归渲染函数
This commit is contained in:
14
stage04/index.html
Normal file
14
stage04/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang='zh-cn'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<title>Stage 04: 模拟异步接口</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="number" id="userId" placeholder="用户 ID" />
|
||||
<button id="loadBtn">加载用户</button>
|
||||
<div id="minivue"></div>
|
||||
<script src="./index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
103
stage04/index.js
Normal file
103
stage04/index.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Stage 04:模拟异步接口
|
||||
* 演示数据从接口获取后再渲染
|
||||
*/
|
||||
|
||||
/**
|
||||
* 根据用户数据生成卡片 DOM 节点
|
||||
* @param {{ name: string, age: number, tag: string }} user
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
function generateUser(user) {
|
||||
const card = document.createElement("div");
|
||||
card.className = "user-card";
|
||||
|
||||
const name = document.createElement("h2");
|
||||
name.textContent = "姓名: " + user.name;
|
||||
|
||||
const age = document.createElement("p");
|
||||
age.textContent = "年龄: " + user.age;
|
||||
|
||||
const tag = document.createElement("span");
|
||||
tag.textContent = user.tag;
|
||||
|
||||
card.appendChild(name);
|
||||
card.appendChild(age);
|
||||
card.appendChild(tag);
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将用户卡片挂载到指定容器
|
||||
* @param {{ name: string, age: number, tag: string }} user
|
||||
* @param {HTMLElement} container
|
||||
*/
|
||||
function renderUser(user, container) {
|
||||
container.appendChild(generateUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染用户列表(先清空容器)
|
||||
* @param {{ name: string, age: number, tag: string }[]} users
|
||||
* @param {HTMLElement} container
|
||||
*/
|
||||
function renderUserList(users, container) {
|
||||
container.innerHTML = ""; // 清空原有内容
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
renderUser(users[i], container);
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟数据库
|
||||
const multiUser = [
|
||||
{ name: "小明", age: 18, tag: "学生" },
|
||||
{ name: "小王", age: 19, tag: "学生" },
|
||||
{ name: "小李", age: 20, tag: "学生" },
|
||||
{ name: "小孙", age: 56, tag: "校长" },
|
||||
{ name: "小赵", age: 43, tag: "老师" },
|
||||
];
|
||||
|
||||
/**
|
||||
* 模拟异步获取用户数据
|
||||
* @param {number} id
|
||||
* @returns {Promise<{ name: string, age: number, tag: string }[]>}
|
||||
*/
|
||||
async function getUser(id) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
const count = Math.min(Math.max(1, id), multiUser.length);
|
||||
return multiUser.slice(0, count);
|
||||
}
|
||||
|
||||
const root = document.getElementById("minivue");
|
||||
const loadBtn = /** @type {HTMLButtonElement} */ (
|
||||
document.getElementById("loadBtn")
|
||||
);
|
||||
const userIdInput = /** @type {HTMLInputElement} */ (
|
||||
document.getElementById("userId")
|
||||
);
|
||||
|
||||
userIdInput.value = "1";
|
||||
|
||||
loadBtn.addEventListener("click", async () => {
|
||||
const rawValue = userIdInput.value.trim();
|
||||
const id = parseInt(rawValue, 10);
|
||||
|
||||
if (isNaN(id) || id < 1) {
|
||||
alert("请输入一个大于 0 的数字 ID");
|
||||
return;
|
||||
}
|
||||
|
||||
loadBtn.disabled = true;
|
||||
loadBtn.textContent = "加载中...";
|
||||
|
||||
try {
|
||||
const users = await getUser(id);
|
||||
renderUserList(users, root);
|
||||
} catch (err) {
|
||||
console.error("加载失败", err);
|
||||
alert("加载失败,请重试");
|
||||
} finally {
|
||||
loadBtn.disabled = false;
|
||||
loadBtn.textContent = "加载用户";
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user