《前端基础实战:从零搭建用户列表,掌握前后端分离核心思想》

从零搭建用户列表:一个完整的前后端分离项目实战

本文将带你从零开始,使用原生HTML/CSS/JS配合json-server,完成一个用户列表展示功能。涵盖语义化HTML、DOM编程、模块化思想、后端Mock数据等核心知识点。

写在前面

最近在整理前端基础知识时,发现很多同学虽然能用框架快速搭建页面,但对底层的HTML语义、DOM操作、模块化设计等概念却掌握不牢。这篇文章从一个简单的用户列表需求出发,完整记录了我的开发思路和技术选型,希望能帮助大家夯实基础。

项目结构

bash 复制代码
project/
├── fe/                    # 前端目录
│   ├── index.html        # 页面结构
│   ├── common.js         # JS逻辑
│   └── style.css         # 样式(可选)
├── backend/              # 后端目录
│   ├── package.json      # 项目配置
│   └── db.json          # 模拟数据库
└── README.md

📚 知识点:为什么这样组织目录?

  • 前后端分离febackend可以分别部署在不同的服务器
  • 职责单一:每个文件只做一件事,符合软件工程原则
  • 便于协作:前端和后端可以并行开发,互不干扰

一、HTML 结构设计

语义化标签优先

很多同学写页面喜欢 div 一把梭,但语义化标签对SEO和代码可读性都更有好:

html 复制代码
<header>页面头部</header>
<main class="container">
    <aside>侧边栏</aside>
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <!-- 主要内容 -->
        </div>
    </div>
    <aside>右侧边栏</aside>
</main>
<footer>页面底部</footer>

📚 知识点详解:语义化标签

标签 语义 对SEO的影响 替代的div方案
<header> 页眉/区块头部 告诉搜索引擎这是导航区域 <div class="header">
<main> 页面主体内容 标识核心内容,一个页面只有一个 <div class="main">
<aside> 侧边栏/辅助信息 表示与主内容相关的辅助信息 <div class="sidebar">
<footer> 页脚/版权信息 标识页面底部信息区域 <div class="footer">
<nav> 导航链接 标识网站导航区域 <div class="nav">

为什么语义化很重要?

  1. 搜索引擎优化(SEO):谷歌爬虫给语义化标签更高的权重
  2. 无障碍访问(a11y):屏幕阅读器可以快速定位页面结构
  3. 代码可维护性:其他开发者接手时能快速理解页面结构
  4. 浏览器默认样式:部分标签自带合理的默认样式

Table 的正确写法

表格一定要区分 theadtbody,这不仅让结构清晰,也方便后续JS操作:

html 复制代码
<table class="table" id="user-table">
    <thead>
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>昵称</th>
            <th>家乡</th>
        </tr>
    </thead>
    <tbody></tbody>  <!-- JS动态填充内容 -->
</table>

📚 知识点详解:表格标签

css 复制代码
table(表格容器)
├── thead(表头区域,0或1个)
│   └── tr(表格行)
│       └── th(表头单元格,自动加粗居中)
├── tbody(表格主体,0或多个)
│   └── tr
│       └── td(普通单元格)
└── tfoot(表尾区域,0或1个,可选)
    └── tr
        └── td

th 与 td 的区别:

  • <th>(Table Header):表头单元格,默认字体加粗、居中,表示该列的含义
  • <td>(Table Data):普通数据单元格,默认左对齐、普通字重

为什么JS要操作tbody而不是table?

  • 只刷新数据区域,表头保持不变
  • 避免意外破坏表格结构
  • 性能更好(只重新渲染tbody部分)

盒模型思维

写HTML时先搭盒子框架,再填充内容。container 固定宽度左右留白,row 表示一行,这是经典的PC端布局思路。

📚 知识点详解:CSS盒模型

css 复制代码
┌─────────────────────────────────────┐
│            margin(外边距)           │
│  ┌───────────────────────────────┐  │
│  │         border(边框)          │  │
│  │  ┌─────────────────────────┐  │  │
│  │  │     padding(内边距)     │  │  │
│  │  │  ┌───────────────────┐  │  │  │
│  │  │  │    content(内容)   │  │  │  │
│  │  │  └───────────────────┘  │  │  │
│  │  └─────────────────────────┘  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘

块级元素 vs 行内元素:

类型 特点 常见标签 宽度
块级元素 独占一行,可设宽高 <div><p><header><main> 默认100%
行内元素 与其他元素同行,不可设宽高 <span><a><strong> 内容撑开

二、CSS 与 Bootstrap

直接引入 Bootstrap 3 快速获得样式支持,省去手写大量CSS的时间:

html 复制代码
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">

Bootstrap的栅格系统非常实用:col-md-6 col-md-offset-3 表示在中等屏幕上占据一半宽度并居中。

📚 知识点详解:Bootstrap栅格系统

Bootstrap把一行(row)分成12等份:

类名 含义 宽度计算
col-md-4 中等屏幕占4格 4/12 = 33.33%
col-md-6 中等屏幕占6格 6/12 = 50%
col-md-12 中等屏幕占12格 100%
col-md-offset-3 向右偏移3格 产生左边距

响应式断点:

  • col-xs-*:超小屏幕(手机,<768px)
  • col-sm-*:小屏幕(平板,≥768px)
  • col-md-*:中等屏幕(桌面,≥992px)
  • col-lg-*:大屏幕(宽屏,≥1200px)

CDN工作原理:

  1. 浏览器解析到<link>标签
  2. 向CDN服务器发起HTTP请求
  3. 下载bootstrap.min.css文件
  4. 解析CSS并应用到页面

为什么用CDN?

  • 速度快:CDN就近分配节点
  • 缓存共享:访问其他使用同一CDN的网站无需重新下载
  • 节省带宽:不占用自己服务器流量
  • 并发加载:不同域名可并行下载

三、JavaScript DOM 编程

模块化思维

不要把代码都塞在一个文件里。common.js 专门处理前端逻辑,与HTML结构分离,便于维护和扩展。

📚 知识点详解:模块化设计

设计原则 说明 本例体现
单一职责 一个模块只做一件事 HTML管结构,CSS管样式,JS管逻辑
高内聚 模块内部紧密相关 common.js只处理用户列表相关逻辑
低耦合 模块之间依赖少 通过ID/class连接,不直接依赖

动态渲染表格

核心步骤:找到挂载点 → 遍历数据 → 动态生成HTML

javascript 复制代码
// 获取tbody元素作为挂载点
const oBody = document.querySelector('.table tbody');

let i = 1;
for (let user of users) {
    oBody.innerHTML += `
        <tr>
            <td>${i}</td>
            <td>${user.name}</td>
            <td>${user.nickname}</td>
            <td>${user.hometown}</td>
        </tr>
    `;
}

📚 知识点详解:DOM操作

DOM树结构:

css 复制代码
document(根节点)
  └─ html(<html>)
      └─ body(<body>)
          └─ main.container
              └─ div.row
                  └─ div.col-md-6
                      └─ table
                          ├─ thead
                          └─ tbody ← querySelector找到这里

querySelector vs 其他选择器:

javascript 复制代码
// 返回第一个匹配的元素
document.querySelector('.table tbody')

// 返回所有匹配的元素(NodeList)
document.querySelectorAll('td')

// 通过ID获取(最快)
document.getElementById('user-table')

// 通过类名获取
document.getElementsByClassName('table')

innerHTML 的工作原理:

  1. 浏览器解析传入的HTML字符串
  2. 构建新的DOM节点
  3. 替换原有的子节点

⚠️ 性能注意事项:

javascript 复制代码
// ❌ 性能差:每次循环都重新解析
for (let user of users) {
    oBody.innerHTML += '<tr>...</tr>';
}

// ✅ 性能好:一次构建,一次插入
let html = '';
for (let user of users) {
    html += '<tr>...</tr>';
}
oBody.innerHTML = html;

ES6 语法亮点

  • for...of 循环:比传统 for (let i=0; i<arr.length; i++) 更简洁
  • 模板字符串:用反引号 + ${变量} 替代字符串拼接,可读性暴增

📚 知识点详解:ES6语法

数组遍历方法对比:

javascript 复制代码
// 传统for循环(需要索引时使用)
for (let i = 0; i < users.length; i++) {
    console.log(users[i]);
}

// for...of(只需要值,不需要索引)
for (let user of users) {
    console.log(user.name);
}

// forEach(函数式编程)
users.forEach(user => {
    console.log(user.name);
});

// map(返回新数组)
const names = users.map(user => user.name);

模板字符串特性:

javascript 复制代码
// 传统拼接(难写、难读)
const html = '<tr><td>' + user.id + '</td><td>' + user.name + '</td></tr>';

// 模板字符串(优雅、支持换行)
const html = `
    <tr>
        <td>${user.id}</td>
        <td>${user.name}</td>
    </tr>
`;

四、后端模拟:json-server

前端开发经常遇到后端接口还没好的情况,json-server 可以快速Mock一个REST API。

初始化项目

bash 复制代码
cd backend
npm init -y
npm install json-server

📚 知识点详解:npm包管理

package.json的作用:

json 复制代码
{
  "name": "backend",           // 项目名称
  "version": "1.0.0",          // 版本号(语义化版本)
  "description": "",           // 项目描述
  "main": "index.js",          // 入口文件
  "scripts": {                 // 自定义命令
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],              // 关键词
  "author": "",                // 作者
  "license": "ISC",            // 开源协议
  "dependencies": {            // 生产环境依赖
    "json-server": "^0.17.0"   // ^表示兼容版本
  }
}

npm install 做了什么?

  1. 读取package.json中的dependencies
  2. 下载依赖包到node_modules目录
  3. 生成package-lock.json锁定版本

创建 db.json

json 复制代码
{
  "users": [
    {
      "id": 1,
      "name": "昌哥",
      "hometown": "南昌",
      "nickname": "昌哥nb666"
    },
    {
      "id": 2,
      "name": "胡航",
      "hometown": "南昌",
      "nickname": "航哥"
    }
  ]
}

📚 知识点详解:JSON格式

JSON语法规则:

  • 键名必须用双引号包裹
  • 字符串值必须用双引号
  • 数字、布尔值、null不需要引号
  • 不能有注释
  • 最后一个属性后面不能有逗号

数据类型:

类型 示例 说明
字符串 "昌哥" 双引号包裹
数字 25 整数或浮点数
布尔值 true true或false
数组 [1, 2, 3] 方括号
对象 {"name": "昌哥"} 花括号
null null 空值

启动服务

bash 复制代码
npx json-server db.json --port 3000

访问 http://localhost:3000/users 就能拿到JSON数据。

📚 知识点详解:REST API

HTTP方法 端点 功能 请求体
GET /users 获取所有用户
GET /users/1 获取id=1的用户
POST /users 新增用户 {"name": "新用户"}
PUT /users/1 完整更新id=1 全量数据
PATCH /users/1 部分更新id=1 {"nickname": "新昵称"}
DELETE /users/1 删除id=1

npx是什么?

  • npm 5.2+ 自带的工具
  • 直接运行node_modules/.bin下的命令
  • 不需要全局安装json-server

五、前后端联调

fetch 发起网络请求,拿到数据后渲染到页面:

javascript 复制代码
fetch('http://localhost:3000/users')
    .then(response => response.json())
    .then(data => {
        users = data;
        renderTable();  // 重新执行渲染逻辑
    });

📚 知识点详解:fetch API和异步编程

fetch执行流程:

scss 复制代码
fetch() 发起请求
    ↓(异步,不阻塞后续代码)
浏览器发送HTTP请求
    ↓
服务器返回响应
    ↓
第一个.then() 拿到Response对象
    ↓
调用.json() 解析JSON
    ↓
第二个.then() 拿到实际数据
    ↓
执行渲染逻辑

Response对象常用属性和方法:

javascript 复制代码
fetch(url).then(response => {
    response.status      // HTTP状态码,200表示成功
    response.ok          // 布尔值,status在200-299之间为true
    response.headers     // 响应头信息
    response.json()      // 解析为JSON对象
    response.text()      // 解析为字符串
    response.blob()      // 解析为二进制数据
})

Promise的三种状态:

状态 含义 触发时机
pending 进行中 初始状态
fulfilled 成功 调用resolve()
rejected 失败 调用reject()

async/await语法糖:

javascript 复制代码
// 等价于上面的fetch写法,但更直观
async function loadUsers() {
    const response = await fetch('http://localhost:3000/users');
    const data = await response.json();
    users = data;
    renderTable();
}

六、完整数据流图解

markdown 复制代码
1. 用户打开页面
   ↓
2. 浏览器加载index.html
   ↓
3. 解析HTML,构建DOM树
   ↓
4. 遇到<link>加载Bootstrap CSS
   ↓
5. 遇到<script>加载并执行common.js
   ↓
6. common.js执行fetch请求
   ↓
7. 请求到达json-server
   ↓
8. json-server读取db.json
   ↓
9. 返回JSON数据给前端
   ↓
10. JS遍历数据,生成HTML字符串
    ↓
11. 设置tbody.innerHTML
    ↓
12. 浏览器重新渲染表格
    ↓
13. 用户看到用户列表

知识小结

知识点 要点 代码体现
HTML语义化 用语义标签替代div <header><main><aside><footer>
表格语义化 区分表头和主体 <thead> + <tbody>
DOM查询 用选择器查找元素 document.querySelector('.table tbody')
动态渲染 用innerHTML插入内容 oBody.innerHTML += ...
模块化 代码按职责拆分 HTML结构 + JS逻辑 + CSS样式
后端模拟 用json-server npx json-server db.json --port 3000
网络请求 用fetch获取数据 fetch(url).then(res => res.json())
异步处理 Promise处理异步 .then() 链式调用

常见问题排查指南

问题 可能原因 解决方法
表格不显示 找不到tbody 检查选择器是否正确
数据不更新 fetch是异步的 确认渲染在.then回调中
中文乱码 缺少meta标签 添加<meta charset="UTF-8">
跨域报错 不同端口访问 json-server默认支持CORS
页面空白 JS语法错误 打开F12控制台查看
连接失败 json-server未启动 运行npx json-server db.json --port 3000

写在最后

这个项目虽然简单,但涵盖了Web开发的核心流程。打好HTML语义、DOM操作、模块化设计这些基础,后续学习React/Vue等框架会事半功倍。

学习路径建议:

  1. 手敲一遍代码,不要复制粘贴
  2. 修改参数观察变化,理解每一行
  3. 尝试添加新功能(搜索、分页、添加用户)
  4. 理解原理后再学框架

如果觉得有收获,欢迎点赞收藏!


项目源码已整理,需要的小伙伴可以私信我~

相关推荐
lightqjx5 小时前
【前端】前端学习四之JavaScript(Web API -- DOM)
前端·javascript·学习
zzqssliu5 小时前
Vue3 + Pinia 重构跨境代购前端:从taocarts的React方案学到的状态管理心得
前端·react.js·重构
IT_陈寒5 小时前
SpringBoot自动配置偷偷给我埋了个坑
前端·人工智能·后端
PieroPc5 小时前
通用产品标签打印 (为制衣厂 打印纸箱错印或不足 补打修改纸箱通用程序)html版
前端·javascript·vue.js
专注API从业者5 小时前
用 Open Claw + 淘宝商品接口,快速实现电商商品监控与智能选品(附完整代码)
大数据·前端·数据结构·数据库
muddjsv5 小时前
前端开发语言使用流行度排行与分析
前端·javascript·typescript
步十人6 小时前
【JWT】验证令牌的使用
前端·bootstrap·html
吃好睡好便好6 小时前
用if…elseif…end语句输出成绩等级
开发语言·前端·javascript·数据库·学习·matlab·信息可视化