告别"散装代码":一个前端学习者的首个"模块化"全栈项目实战
从"div满天飞"到"语义化+前后端分离",我的代码整洁之路
大家好,我是仍在全栈路上摸索的"小望"。
还记得刚开始写页面的时候,我的"项目"就是一个 index.html 文件。里面从上到下塞满了 <style> 标签写的 CSS、<script> 标签堆的 JS 逻辑、还有直接写在 </table> 里的假数据......改一个按钮颜色,要在密密麻麻的代码里翻半天;想加个新功能,又怕碰坏了哪里。
这种把所有代码"一锅炖"的方式,我给它起了个名字叫 "散装代码" 。它不仅让我调试时头大,更让我觉得前端这行就是个体力活。
直到最近,我强迫自己开始实践 "模块化拆分" 和 "前后端分离" 的思想,把项目拆分成清晰的文件目录,让 HTML、CSS、JS 各司其职,甚至用 json-server 模拟了一个真正的数据接口。
当我把那个"散装"的用户列表页面,改造成一个通过接口动态获取数据、结构清晰、文件职责分明的小应用时,那种"代码终于被我理顺了"的成就感,是之前从未有过的。
今天这篇文章,就是想和你分享我从 "散装代码" 到 "模块化全栈" 的完整实践过程。代码绝对不复杂,思路新手也能听懂。让我们一起告别混乱,写出更"体面"的代码。
一、痛点先行:你的代码还在"一锅炖"吗?
先来看看我刚入门时的"杰作"------一个典型的单体文件:
html
xml
<!-- 一个文件搞定一切?那是噩梦的开始 -->
<!DOCTYPE html>
<html>
<head>
<style>
/* 几百行CSS塞在这里... */
body { margin: 0; /* ... */ }
.header { /* ... */ }
/* 找样式找到眼花 */
</style>
</head>
<body>
<div class="header">用户列表</div>
<div class="content">
<table id="userTable">
<!-- 假数据直接写死 -->
<tr>
<td>1</td>
<td>张三</td>
<td>上海</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>南昌</td>
</tr>
</table>
</div>
<script>
// 几百行JS逻辑也塞在这里...
function deleteUser() { /* 复杂逻辑 */ }
function addUser() { /* 更多逻辑 */ }
// 改一个功能,大海捞针
</script>
</body>
</html>
这暴露了三个大问题:
- 不好维护:改个样式要在几百行 CSS 里翻找,修个 JS bug 要滚动半天
- 不好扩展:想加个"新增用户"功能,HTML、JS、甚至假数据都要改,牵一发动全身
- 不好协作:一个人写还好,团队合作时天天合并冲突,痛不欲生
核心思想:解决方案就是模块化拆分------每个文件夹有清晰职责,每个文件只做一件事。
二、项目重构:建立"各司其职"的目录结构
让我们从"大泥球"变成"独立小房间"。这是我的最终项目结构:
text
perl
my-project/
├── fe/ # 📁 前端目录 - 只管展示和交互
│ ├── index.html # 页面骨架(结构)
│ └── common.js # 页面行为(逻辑)
│
└── backend/ # 📁 后端目录 - 只管提供数据
├── db.json # 模拟数据库(数据)
└── package.json # 后端配置文件
各模块职责一览
| 目录/文件 | 职责 | 包含什么 |
|---|---|---|
fe/index.html |
页面结构 | HTML 标签、Bootstrap 类名 |
fe/common.js |
交互逻辑 | 获取数据、渲染表格、事件处理 |
backend/db.json |
模拟数据 | JSON 格式的用户信息 |
backend/package.json |
后端配置 | 项目依赖、启动脚本 |
前后端分离的核心:前端专注用户看到的东西,后端专注提供数据。改前端样式完全不影响后端逻辑,换后端技术栈也轻轻松松。
三、打磨前端(一):别让 div "满天飞"
有了目录结构,我们先写前端页面。语义化标签是第一课。
❌ 糟糕的"div泛滥"写法
html
ini
<div class="header">头部</div>
<div class="main">
<div class="sidebar">侧栏</div>
<div class="content">内容</div>
</div>
<div class="footer">底部</div>
✅ 优雅的"语义化"写法
html
css
<header>头部</header>
<main>
<aside>侧栏</aside>
<article>内容</article>
</main>
<footer>底部</footer>
语义化的好处:
- 搜索引擎能读懂页面结构(SEO 友好)
- 屏幕阅读器等无障碍设备能正确解析
- 代码可读性大大提升,一看标签就知道这块是做什么的
盒模型思维:先搭骨架,再填内容
我采用了 Bootstrap 框架 的栅格系统来布局,核心就是 行列(row/col) 概念:
html
xml
<!-- container:固定宽度容器,左右自动留白 -->
<main class="container">
<!-- row:一行 -->
<div class="row">
<!-- col-md-6:中等屏幕占6列(半行宽)-->
<!-- col-md-offset-3:向右偏移3列,实现水平居中 -->
<div class="col-md-6 col-md-offset-3">
<table class="table table-striped">
<!-- 表格内容 -->
</table>
</div>
</div>
</main>
布局口诀 :
container做外框,row分 12 列,col占宽度,offset做偏移。PC、iPad、手机自动适配,不用手写媒体查询!
四、打磨前端(二):让表格"活"过来
静态页面不够,还得动态渲染数据。这就得靠 JavaScript 操作 DOM 了。
DOM 是什么?
当浏览器解析 HTML,会在内存中构建一棵树(Document Object Model)。每个 HTML 标签都变成一个 JS 对象,我们可以通过 JS 找到这些节点,增删改查。
javascript
less
// 就像拿着遥控器操控页面
const tbody = document.querySelector('#user-table-body'); // 找到表格身体
tbody.innerHTML = '<tr><td>1</td><td>张三</td><td>上海</td></tr>'; // 改变内容
数据驱动渲染(重要思维)
不要手动修改每一个单元格,而是维护数据 → 根据数据重新渲染整个表格。
这是我写的 common.js 核心逻辑:
javascript
less
// 1. 获取数据
const users = await fetch('http://localhost:3000/users').then(res => res.json());
// 2. 根据数据生成HTML
let html = '';
users.forEach(user => {
html += `<tr><td>${user.id}</td><td>${user.name}</td><td>${user.hometown}</td></tr>`;
});
// 3. 一次性更新页面
document.querySelector('#user-table-body').innerHTML = html;
性能小贴士 :循环拼接字符串,最后一次性
innerHTML,比循环中一次次操作 DOM 快得多!
五、火速搭后端:json-server,前端er的救星
前端需要接口才能调试,但后端开发还没写好怎么办?json-server 让你 30 秒拥有完整 REST API!
步骤1:初始化后端项目
bash
bash
cd backend
npm init -y # 生成 package.json
步骤2:安装 json-server
bash
vbscript
npm install json-server
步骤3:配置启动脚本
在 package.json 中添加:
json
json
"scripts": {
"dev": "json-server --watch db.json --port 3000"
}
步骤4:创建模拟数据库 db.json
json
json
{
"users": [
{ "id": 1, "name": "张三", "nickname": "三哥", "hometown": "上海" },
{ "id": 2, "name": "李四", "nickname": "四哥", "hometown": "南昌" },
{ "id": 3, "name": "王五", "nickname": "五哥", "hometown": "北京" }
]
}
步骤5:启动服务
bash
arduino
npm run dev
访问 http://localhost:3000/users,你就能看到 JSON 数据了!增删改查接口全部自动生成,爽翻!
六、完整代码:拿来即用的"全栈"模板
前端完整代码(fe/index.html)
html
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户管理系统 - 模块化全栈实战</title>
<!-- Bootstrap样式库:快速美化 -->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<!-- 语义化头部 -->
<header class="text-center" style="padding: 20px; background: #f8f9fa;">
<h1>👥 用户信息管理</h1>
<p>数据来自 json-server 模拟后端接口</p>
</header>
<!-- 主体:container + 行列布局 -->
<main class="container" style="margin-top: 30px; min-height: 60vh;">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<table class="table table-bordered table-striped" id="user-table">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>昵称</th>
<th>家乡</th>
</tr>
</thead>
<tbody id="user-table-body">
<!-- JS动态插入数据 -->
<tr><td colspan="4" class="text-center">⏳ 加载中...</td></tr>
</tbody>
</table>
</div>
</div>
</main>
<!-- 语义化底部 -->
<footer class="text-center" style="padding: 15px; background: #f8f9fa; margin-top: 20px;">
<p>📌 项目演示 | 前端: HTML5 + Bootstrap | 后端: json-server</p>
</footer>
<!-- 引入JS模块 -->
<script src="./common.js"></script>
</body>
</html>
前端逻辑(fe/common.js)
javascript
ini
/**
* 用户列表管理模块
* 职责:获取后端数据 + 渲染到表格
* 核心思想:数据驱动视图
*/
const API_URL = 'http://localhost:3000/users';
/**
* 从后端获取用户数据
*/
async function fetchUsers() {
try {
const response = await fetch(API_URL);
if (!response.ok) throw new Error('网络请求失败');
const users = await response.json();
return users;
} catch (error) {
console.error('获取用户数据失败:', error);
return [];
}
}
/**
* 渲染用户列表到表格
* @param {Array} users 用户数组
*/
function renderUserTable(users) {
const tbody = document.querySelector('#user-table-body');
if (!users || users.length === 0) {
tbody.innerHTML = '<tr><td colspan="4" class="text-center">📭 暂无数据</td></tr>';
return;
}
// 核心:遍历数据,生成HTML字符串
let html = '';
users.forEach(user => {
html += `
<tr>
<td>${user.id}</td>
<td><strong>${user.name}</strong></td>
<td>${user.nickname || '--'}</td>
<td>📍 ${user.hometown}</td>
</tr>
`;
});
// 一次性更新DOM(性能优化)
tbody.innerHTML = html;
}
/**
* 初始化页面
*/
async function init() {
const tbody = document.querySelector('#user-table-body');
tbody.innerHTML = '<tr><td colspan="4" class="text-center">⏳ 加载中...</td></tr>';
const users = await fetchUsers();
renderUserTable(users);
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', init);
后端配置(backend/package.json)
json
json
{
"name": "user-management-backend",
"version": "1.0.0",
"description": "用户管理模拟后端",
"main": "index.js",
"scripts": {
"dev": "json-server --watch db.json --port 3000"
},
"keywords": ["mock-api", "json-server", "全栈练习"],
"author": "小王",
"license": "ISC",
"dependencies": {
"json-server": "^1.0.0-beta.15"
}
}
模拟数据(backend/db.json)
json
json
{
"users": [
{
"id": 1,
"name": "张三",
"nickname": "三哥",
"hometown": "上海"
},
{
"id": 2,
"name": "李四",
"nickname": "四哥",
"hometown": "南昌"
},
{
"id": 3,
"name": "王五",
"nickname": "五哥",
"hometown": "北京"
}
]
}
七、运行项目:见证属于你的"全栈"时刻
1️⃣ 启动后端
bash
arduino
cd backend
npm run dev
看到这个输出就成功了:
text
arduino
JSON Server running at http://localhost:3000
2️⃣ 打开前端页面
直接用浏览器打开 fe/index.html,或者用 VS Code 的 Live Server 右键启动。
3️⃣ 见证奇迹
页面自动从 http://localhost:3000/users 获取数据,并渲染成表格。试着修改 db.json 里的数据,刷新页面,表格内容自动更新!
这一刻,你跑通了一个完整的前后端分离项目!
八、总结与感悟:迈出"全栈"第一步后的三点思考
核心知识点速查表
| 模块 | 技术点 | 一句话总结 |
|---|---|---|
| 工程化 | 模块化拆分 | 一个文件只做一件事,职责清晰 |
| HTML | 语义化标签 | header/main/footer,别滥用 div |
| CSS布局 | 盒模型 + 行列 | container 做容器,row 分 12 列 |
| 样式框架 | Bootstrap | 引入类名快速美化,专注业务 |
| JS核心 | DOM编程 | 找到节点,动态改内容 |
| 前端架构 | 数据驱动视图 | 维护数据,批量渲染整个表格 |
| 后端 | json-server | JSON 文件秒变 RESTful API |
我的三点感悟
- 结构是灵魂:语义化标签和模块化目录,比炫技的 CSS 重要 100 倍。代码首先是给人读的,其次才是给机器运行的。
- 思想是核心:理解"数据驱动"和"前后端分离",比学会某个框架更持久。框架会过时,但思想不会。
- 动手是真理 :跟着文章跑通这个项目,你获得的成就感会推动你走得更远。全栈不是天赋,而是一步步积累的信心。
这个小项目跑通后,我算是真正理解了前后端分离 是什么感觉。下一步我准备加上表单新增用户 、删除功能 ,再用 localStorage 做个本地缓存。
全栈之路这才刚刚开始,希望这篇文章能帮你迈出第一步。代码全部贴出,复制粘贴就能跑。如果遇到跨域问题,json-server 默认支持 CORS,不用额外配置。
如果你跑通了,欢迎在评论区告诉我!也欢迎分享你用这个模板做的改进~
告别"散装代码",从今天开始。
🏷️ 掘金标签 :#前端 #JavaScript #Node.js #全栈开发 #HTML5
如果这篇文章帮到了你,欢迎点赞、收藏、评论三连~ 你的支持是我继续分享的动力!