From fc87cf4622250e61152b926015790b221b8aa616 Mon Sep 17 00:00:00 2001
From: zzy <2450266535@qq.com>
Date: Sat, 2 May 2026 12:16:03 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=89=8D=E7=AB=AF?=
=?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=9F=BA=E7=A1=80=E9=85=8D=E7=BD=AE=E5=92=8C?=
=?UTF-8?q?=E9=98=B6=E6=AE=B5=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
添加 .editorconfig 配置文件用于统一编辑器设置,包括缩进风格、
换行符、字符集等规范。
添加 jsconfig.json 配置文件用于 JavaScript 项目的编译选项,
启用类型检查和模块解析配置。
添加 stage00 到 stage03 四个阶段的 HTML 和 JavaScript 示例:
- stage00: 基础 HTML 结构演示
- stage01: 纯命令式 DOM 操作实现用户卡片
- stage02: 声明式渲染方式重构用户卡片生成
- stage03: 扩展支持列表渲染多个用户数据
每个阶段都包含对应的 HTML 入口文件和 JavaScript 实现逻辑,
逐步展示从命令式到声明式渲染的演进过程。
---
.editorconfig | 12 +++++++++++
jsconfig.json | 17 ++++++++++++++++
stage00/index.html | 15 ++++++++++++++
stage01/index.html | 12 +++++++++++
stage01/index.js | 24 ++++++++++++++++++++++
stage02/index.html | 12 +++++++++++
stage02/index.js | 42 ++++++++++++++++++++++++++++++++++++++
stage03/index.html | 12 +++++++++++
stage03/index.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 196 insertions(+)
create mode 100644 .editorconfig
create mode 100644 jsconfig.json
create mode 100644 stage00/index.html
create mode 100644 stage01/index.html
create mode 100644 stage01/index.js
create mode 100644 stage02/index.html
create mode 100644 stage02/index.js
create mode 100644 stage03/index.html
create mode 100644 stage03/index.js
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..88bf97c
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = crlf
+charset = utf-8
+trim_trailing_whitespace = false
+insert_final_newline = false
\ No newline at end of file
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 0000000..25b7dc7
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "checkJs": true,
+ "strict": false,
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "moduleDetection": "force",
+ },
+ "include": [
+ "*.js",
+ "stage*/**/*.js"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/stage00/index.html b/stage00/index.html
new file mode 100644
index 0000000..1f48962
--- /dev/null
+++ b/stage00/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Stage 00 using html
+
+
+
+
+
diff --git a/stage01/index.html b/stage01/index.html
new file mode 100644
index 0000000..1942744
--- /dev/null
+++ b/stage01/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Stage 01 - 命令式 DOM
+
+
+
+
+
+
diff --git a/stage01/index.js b/stage01/index.js
new file mode 100644
index 0000000..cea5ab2
--- /dev/null
+++ b/stage01/index.js
@@ -0,0 +1,24 @@
+/**
+ * Stage 01:纯命令式 DOM 操作
+ * 每一步都直接创建、组装、插入节点
+ */
+
+const card = document.createElement("div");
+card.className = "user-card";
+
+const nameEl = document.createElement("h2");
+nameEl.textContent = "姓名: 小明";
+
+const ageEl = document.createElement("p");
+ageEl.textContent = "年龄: 18";
+
+const tagEl = document.createElement("span");
+tagEl.textContent = "学生";
+
+card.appendChild(nameEl);
+card.appendChild(ageEl);
+card.appendChild(tagEl);
+
+const root = document.getElementById("minivue");
+console.assert(root != null, "容器 #minivue 未找到");
+root.appendChild(card);
diff --git a/stage02/index.html b/stage02/index.html
new file mode 100644
index 0000000..e2a1f51
--- /dev/null
+++ b/stage02/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Stage 02: 声明式渲染
+
+
+
+
+
+
diff --git a/stage02/index.js b/stage02/index.js
new file mode 100644
index 0000000..61f5e7c
--- /dev/null
+++ b/stage02/index.js
@@ -0,0 +1,42 @@
+/**
+ * Stage 02:声明式渲染
+ * 把“数据 → DOM”封装为函数,数据变了只需重新调用函数
+ */
+
+/**
+ * 根据用户数据生成卡片 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));
+}
+
+const user = { name: "小明", age: 18, tag: "学生" };
+
+const root = document.getElementById("minivue");
+renderUser(user, root);
diff --git a/stage03/index.html b/stage03/index.html
new file mode 100644
index 0000000..638b6e4
--- /dev/null
+++ b/stage03/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Stage 03: 列表渲染
+
+
+
+
+
+
diff --git a/stage03/index.js b/stage03/index.js
new file mode 100644
index 0000000..0b9ebca
--- /dev/null
+++ b/stage03/index.js
@@ -0,0 +1,50 @@
+/**
+ * Stage 03:列表渲染
+ * 用循环对数组中的每个数据项调用渲染函数
+ */
+
+/**
+ * 根据用户数据生成卡片 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));
+}
+
+const multiUser = [
+ { name: "小明", age: 18, tag: "学生" },
+ { name: "小王", age: 19, tag: "学生" },
+ { name: "小李", age: 20, tag: "学生" },
+ { name: "小孙", age: 56, tag: "校长" },
+ { name: "小赵", age: 43, tag: "老师" },
+];
+
+const root = document.getElementById("minivue");
+for (let i = 0; i < multiUser.length; i++) {
+ renderUser(multiUser[i], root);
+}