JS教程:没有Vue、没有任何框架,纯原生JS**,完整案例。

目标说明

需求:没有Vue、没有任何框架,纯原生JS,完整案例。
包含JS全部基础核心知识点,智慧城市大屏比喻,为后面学习Vue3+TS打基础。
业务场景:智慧小区住户登记大屏(登记住户、展示列表、删除住户、统计欠费人数、表单校验、网络模拟请求)
知识点覆盖:let/const、基础类型、数组、对象、函数、箭头函数、if判断、循环、DOM查询、事件、表单校验、this、try/catch、异步、JSON、console调试。

比喻回顾
HTML:公示大屏原始图纸
DOM:内存里建好的大屏楼房(Elements面板)
JS:大屏运维员
document:物业总管

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>原生JS智慧小区住户大屏(无Vue)</title>
  <style>
    .item {margin:4px 0;padding:4px;border:1px solid #aaa;}
    .del-btn {margin-left:10px;color:red;cursor:pointer;}
  </style>
</head>
<body>
  <h2>🏘️ 阳光智慧小区 - 住户登记大屏(原生JS版本)</h2>
  <!-- 输入表单 -->
  <div>
    姓名:<input id="nameInput" placeholder="输入住户姓名">
    房号:<input id="roomInput" placeholder="输入房号数字">
    <input type="checkbox" id="feeCheck">已缴物业费
    <button id="addBtn">登记住户</button>
  </div>

  <div>
    <h3>统计信息:<span id="statText"></span></h3>
  </div>

  <!-- 住户列表展示区域(DOM广告牌容器) -->
  <div id="listWrap"></div>

<script>
'use strict'; // 严格模式:约束运维员写代码,禁止乱写,减少低级错误

// ===================== 1. 变量 let / const 收纳盒 =====================
// const:固定收纳盒,内容一旦赋值不能替换
const pageTitle = "阳光智慧小区公示屏";
// let:可修改收纳盒,里面内容后续可以更换
let residentList = []; // 数组:一排档案格子,存放所有住户档案卡片

// 基础数据类型(收纳盒存放的物品)
let demoName = "老王";       // String 文字字符串
let demoRoom = 1201;        // Number 数字
let hasPay = true;          // Boolean 布尔 true/false
let emptyCard = null;       // null:收纳盒手动清空
let unknownVal;             // undefined:收纳盒存在,从未放东西

// ===================== 2. 对象 Object:单张住户档案卡片 =====================
/**
 * 创建住户档案卡片
 * @param {string} name 住户姓名
 * @param {number} room 房号
 * @param {boolean} isPaid 是否缴费
 * @returns 住户对象档案
 */
function createResident(name, room, isPaid) {
  return {
    name: name,
    room: room,
    isPaid: isPaid,
    // 对象方法:卡片自带打招呼动作,this代表当前这张档案卡片
    sayHello: function () {
      console.log(`你好,住户【${this.name}】`);
    }
  }
}

// ===================== 3. 普通函数:打包一套固定任务【表单校验】 =====================
// 任务:校验市民在输入框填写的信息是否合法
function validateInput(nameStr, roomStr) {
  if (!nameStr) {
    return { ok: false, msg: "❌姓名不能为空!" };
  }
  if (isNaN(roomStr) || Number(roomStr) <= 0) {
    return { ok: false, msg: "❌房号必须是大于0的数字!" };
  }
  return { ok: true, msg: "✅校验通过" };
}

// ===================== 4. 箭头函数:简短小任务【筛选欠费住户】 =====================
const getUnpaidResidents = (arr) => {
  let unpaidArr = [];
  // for循环:运维员逐个翻阅档案格子
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].isPaid === false) {
      unpaidArr.push(arr[i]); // push:档案格子末尾新增一张档案卡
    }
  }
  return unpaidArr;
}

// ===================== 5. DOM查询:运维员指挥物业总管document找到大屏广告牌 =====================
const nameDom = document.querySelector("#nameInput");
const roomDom = document.querySelector("#roomInput");
const feeCheckDom = document.querySelector("#feeCheck");
const addBtnDom = document.querySelector("#addBtn");
const listWrapDom = document.querySelector("#listWrap");
const statTextDom = document.querySelector("#statText");

// ===================== 渲染函数:刷新整个住户公示大屏(核心!原生JS需要手动刷新页面) =====================
function renderList() {
  listWrapDom.innerHTML = ""; // 清空广告牌容器
  // 循环遍历所有住户档案,逐个生成DOM广告牌
  for (let j = 0; j < residentList.length; j++) {
    const item = residentList[j];
    // 生成单条住户HTML
    const div = document.createElement("div");
    div.className = "item";
    div.innerHTML = `
      住户:${item.name},房号:${item.room},物业费:${item.isPaid ? "已缴" : "欠费"}
      <span class="del-btn">【删除】</span>
    `;
    // 删除按钮点击事件
    const delBtn = div.querySelector(".del-btn");
    delBtn.onclick = function () {
      // 删除当前这条住户数据
      residentList.splice(j, 1);
      renderList(); // 删除数据后,重新渲染大屏
    }
    listWrapDom.appendChild(div);
    item.sayHello(); // 调用对象方法
  }
  // 更新统计文字
  const unpaidList = getUnpaidResidents(residentList);
  statTextDom.innerText = `总户数:${residentList.length},欠费户数:${unpaidList.length}`;
}

// ===================== 6. 事件监听:监听【登记按钮点击】(用户交互) =====================
addBtnDom.addEventListener("click", async function () {
  try { // try/catch 异常捕获,防止代码出错直接让整个大屏崩溃
    // 获取输入框里面用户填写的值
    const inputName = nameDom.value.trim();
    const inputRoom = roomDom.value.trim();
    const isPaid = feeCheckDom.checked;

    // 执行表单校验
    const checkRes = validateInput(inputName, inputRoom);
    if (!checkRes.ok) {
      alert(checkRes.msg);
      return;
    }

    // 创建住户档案对象
    const newResident = createResident(inputName, Number(inputRoom), isPaid);
    residentList.push(newResident);

    // 【重点】原生JS:数据修改之后,必须手动调用渲染函数更新大屏广告牌!
    renderList();

    // ===================== 7. 异步请求:运维员呼叫城市数据中心API =====================
    // 模拟:把住户档案上报远端服务器(城市数据中心档案室)
    const res = await fetch("[https://jsonplaceholder.typicode.com/posts](https://jsonplaceholder.typicode.com/posts)", {
      method: "POST",
      body: JSON.stringify(newResident) // JSON:把JS档案打包成网络传输格式
    })
    const backData = await res.json();
    console.log("✅总部收到登记,返回回执:", backData);

    // 清空输入框
    nameDom.value = "";
    roomDom.value = "";
    feeCheckDom.checked = false;

  } catch (err) {
    console.error("❌网络上报出错:", err);
    alert("网络故障,住户信息保存到本地成功,上报总部失败!");
  }
})

// 页面加载完成,初始渲染一次空列表
renderList();
</script>
</body>
</html>

✅ 这个原生案例核心逻辑(口述讲解,为Vue铺垫)

重点!这就是Vue出现之前前端的写法:

  1. 我们维护一份内存数据:residentList(档案数组)
  2. 数据变了之后,必须手动调用renderList()去操作DOM,刷新大屏页面
  3. 每次增删住户,都要手动重新生成广告牌、手动操作innerHTML、createElement
  4. 所有DOM操作全部手写;数据和页面视图需要程序员手动同步

痛点(后面Vue3解决的问题,一定要给学员讲)

  • 数据修改,不会自动更新页面,必须自己调用渲染函数刷新DOM;忘记调用,页面就和内存档案不一致。
  • 页面复杂之后,DOM操作代码到处散落,维护麻烦。
  • 每次更新列表,上面示例直接清空容器全部重绘(简单项目够用,复杂页面性能差)>

Vue3的核心改进:响应式数据,数据一变自动更新视图,不用手动写render渲染函数

📖 覆盖知识点清单(黑板板书)

【原生JS案例包含全部基础知识点】
1. 'use strict' 严格模式
2. let / const 变量,5大基础类型:String Number Boolean null undefined
3. Array数组,push、splice数组方法
4. Object对象,this,对象内方法
5. 普通function函数、箭头函数
6. if 判断、for循环
7. DOM:querySelector、createElement、appendChild、innerHTML
8. 事件:addEventListener、click点击事件
9. 表单取值、表单校验
10. try / catch 异常捕获
11. async / await 异步 + fetch网络请求
12. JSON.stringify、JSON解析
13. console.log调试、alert弹窗

📌 上机操作+F12演示步骤

  1. 复制全部代码保存html,浏览器打开
  2. F12打开Elements:新增住户时,会动态新增DOM节点(广告牌)
  3. F12 Console:可以看到打印日志;在这里可以手动修改residentList数组,然后在控制台执行renderList(),页面才会更新```
    residentList.push(createResident("小张",2002,false));
    renderList();

> 
> ✨关键实验:只修改数组,**不执行renderList(),页面不会变!**
> 这就是原生JS最大痛点,Vue自动帮你做这一步。

## 随堂口述总结(一段讲完)

这个案例是Vue诞生之前,前端开发的原生JS标准写法。
我们在内存里保存住户档案数组,当新增、删除住户修改数据后,**必须手动写渲染函数renderList,操作DOM广告牌刷新页面**。原生JS不会自动同步页面和数据。
所有DOM查询、事件绑定、页面更新都需要手写。
后面学习Vue3,就是把这套手动同步的工作交给框架。我们只需要修改响应式收纳盒里面的数据,Vue内部自动完成渲染、更新DOM,不用手写大量DOM操作和render渲染函数。
TS则后续给这些档案对象加上类型约束,防止档案格式写错。

## 课堂思考题

1. 原生JS中,如果修改residentList数组,但是不调用renderList(),页面会更新吗?> 
> 不会,内存数据变了,但是DOM大屏不会自动刷新,必须手动渲染。
2. 原生JS最大麻烦是什么?> 
> 数据和视图需要人工手动同步,每次数据改动都要手动操作DOM更新页面。

---

### 下一步对比演示(下一课,用来引出Vue3)

同一个业务,改成Vue3版本,对比两份代码,学员一眼看懂Vue解决了原生JS的什么麻烦。
要不要我直接写**等价Vue3版本(setup语法糖)**,方便课堂直接对比原生JS代码?
posted @ 2026-10-15 14:36  华腾智算  阅读(6)  评论(0)    收藏  举报
https://damo.alibaba.com/ https://tianchi.aliyun.com/course?spm=5176.21206777.J_3941670930.5.87dc17c9BZNvLL