前后端模块化分离,web盒子布局思维

前言

我是一名刚入门的程序员,最近写了一个"用户聊天"小项目(user-chat)。项目虽小,但把前后端模块化分离的完整流程走了一遍。

一、项目总览:前后端各管各的

先看整个项目的目录结构:

go 复制代码
user-chat/
├── fe/                  ← 前端只碰这个目录
│   ├── index.html       ← 页面结构 + 样式引入
│   └── common.js        ← 页面交互逻辑
├── backend/             ← 后端只碰这个目录
│   ├── db.json          ← 数据源
│   ├── package.json     ← 后端项目描述文件
│   └── package-lock.json
└── readme.md

核心理念:每个文件夹有明确的职责划分,每个文件只做一件事。

  • fe/ 目录:专注前端,只管页面长什么样、用户怎么交互
  • backend/ 目录:专注后端,只管数据存哪里、接口怎么提供

前后端各司其职,互不干扰,通过 HTTP 接口沟通。这就像一个餐厅------前端是大堂服务员(接待客人、展示菜单),后端是后厨(准备食材、做菜),中间通过"订单小票"(HTTP 请求)来传递信息。

为什么不能把所有代码塞进一个文件?

如果代码、功能全堆在一起,会出现三个致命问题:

  • 不好维护:改一个样式要找半天,牵一发而动全身
  • 不好扩展:加一个新功能时,生怕把旧功能改坏了
  • 不好优化:代码像一团乱麻,根本不知道从哪下手

解决方案就是模块化拆分------职责分离之后,每个文件只做一件事,就像乐高积木,可以随意组合、替换、扩展。

二、前端内部也做了"再分离":三件套各司其职

打开 fe/index.html,前端本身也把结构、样式、行为三者做了分离:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- CSS 在头部引入:负责样式 -->
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <!-- HTML 标签:负责结构 -->
    <header>1111</header>
    <main class="container">
        ...
    </main>
    <footer>222</footer>
    <!-- JS 在底部引入:负责行为 -->
    <script src="./common.js"></script>
</body>
</html>

CSS 放在 <head>、JS 放在 <body> 底部------这不是随意放的,而是有讲究的:

技术 作用 类比 引入位置 原因
HTML 负责结构 房子的钢筋骨架 整个文件 所有内容的载体
CSS 负责样式 房子的装修 <head> 里 尽早加载,让用户第一眼就看到好看的页面,体验更好
JS 负责行为 房子的水电系统 <body> 底部 等页面结构渲染完了再加载,不阻塞页面显示

CSS 框架:Bootstrap

你可能注意到了,这个项目没有手写一行 CSS------全靠引入的 Bootstrap 框架:

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

Bootstrap 是 Twitter 开源的 CSS 框架,帮我们准备好了大量开箱即用的样式。对于新手来说,先用框架快速出效果,后面再深入学习 CSS 原理,是高效的学习路径。

三、CSS 布局的三个核心概念

1. Box(盒子模型)------"先写盒子,再写内容"

在 CSS 的世界里,所有可见元素都是矩形盒子。比如代码中的:

html 复制代码
<div class="row col-md-6 col-md-offset-3">
    <table class="table table-striped" id="user-table">
        ...
    </table>
</div>

外层 div 是一个大盒子(容器),里面的 table 是一个小盒子(内容)。布局的思维就是:先规划盒子套盒子的层级关系,再往盒子里填充具体内容。

2. Container(容器)------"中间固定,左右留白"

html 复制代码
<main class="container">

container 是 Bootstrap 提供的布局类,作用是:内容区域的宽度固定,左右两侧自动留白。这样无论用户用的是大屏幕台式机还是小屏幕笔记本,内容始终居中显示------这是从 PC 时代就积累下来的经典布局方案。

3. Row 和 Col(行列布局)------栅格系统

ini 复制代码
row = 一行
col = 一列

Bootstrap 把一行划分为 12 个等份 ,通过 col-md-数字 来控制元素占据的宽度:

html 复制代码
<div class="row col-md-6 col-md-offset-3">
  • col-md-6:占 6 份(即一行的一半宽度)
  • col-md-offset-3:向右偏移 3 份(从而实现居中效果)

这就是栅格系统------实现响应式布局的基石。

四、HTML 世界的两种标签类型

HTML 默认只有两大类标签,理解这个是写出好页面的第一步:

类型 核心特点 用来干什么 例子
块级元素 默认独占一整行 做"盒子",搭建页面骨架 div、header、footer、main、aside、table
行内元素 兄弟之间可以排在同一行,互不干扰 装"内容"(文字、链接、图片) span、a、img、em

代码中就能看到这个规律:

  • header、main、footer、aside、div、table → 都是块级元素,用来搭骨架
  • 这些大盒子里再嵌套内容(文字、表格数据)

语义化标签:拒绝 div 满天飞

新手很容易写成这样:

html 复制代码
<div class="header">头部</div>
<div class="main">内容</div>
<div class="footer">底部</div>

全是 div,虽然也能跑,但就像一本书没有目录、没有章节标题------机器难以理解页面结构,搜索引擎爬虫和屏幕阅读器(视障用户依赖的工具)更是无从下手。

这个项目用了更规范的做法------语义化标签:

html 复制代码
<header>头部</header>    ← 比 <div class="header"> 更有语义
<main>主体内容</main>     ← 比 <div class="main"> 更有语义
<footer>底部</footer>     ← 比 <div class="footer"> 更有语义
<aside>侧边栏</aside>     ← 比 <div class="sidebar"> 更有语义

这些标签和 div 同属块级元素,但名字本身就表达了含义 ------header 就是页头,footer 就是页脚,对人、对机器都更友好。大厂面试经常会问语义化标签,因为这是 Web 标准理解深度的直接体现。

Table 的语义化关键:thead + tbody

html 复制代码
<table class="table table-striped" id="user-table">
    <tbody>
        <tr>
            <td>ID</td>
            <td>姓名</td>
            <td>昵称</td>
            <td>家乡</td>
        </tr>
    </tbody>
</table>

thead(表头)和 tbody(表体)是表格语义化的关键结构。它们告诉浏览器哪些行是表头、哪些行是数据,这对表格的排序、筛选、打印、无障碍访问都至关重要。千万不要省略。

五、<!DOCTYPE html> 和 HTML 文档的本质

两种文本类型

浏览器处理两种文本:

类型 说明
text/plain 纯文本,记事本打开什么样就显示什么样
text/html HTML 标签文本,通过 HTTP 协议传输,由浏览器解析成可视化页面

你的 HTML 文件属于 text/html 类型,浏览器收到后会解析标签、渲染出可视化的网页。

<!DOCTYPE html> 是干嘛的?

html 复制代码
<!DOCTYPE html>

这行的作用是告诉浏览器:请用最新的 HTML5 标准渲染这个页面。如果不写,浏览器会进入"怪异模式"(向后兼容老版本 HTML4 的渲染方式),可能导致样式错乱、布局异常。每个正经的 HTML 文档,第一行一定长这样。

六、DOM 编程:JS 如何动态操控页面

这是前端最核心的底层能力,也是大厂面试的重点考察方向。

DOM 是什么?

DOM = Document Object Model(文档对象模型)

浏览器加载 HTML 后,会把每个 HTML 标签变成 JS 内存中的对象 ,并组织成一棵树状结构:

xml 复制代码
document                              ← 文档对象(整个页面在 JS 中的入口)
  └── document.documentElement        ← 根节点(对应 <html> 标签)
        └── document.body             ← 页面主体(对应 <body> 标签)
              ├── <header>
              ├── <main>
              │     ├── <aside>
              │     └── <div class="row">
              │           └── <table id="user-table">
              │                 └── <tbody>
              │                       └── <tr> x N
              └── <footer>

你可以通过 document.querySelector() 在这棵树上旅行,找到任意节点,然后查看它的子节点、兄弟节点,甚至把它挂载到另一个节点上。

实际代码解读

打开 fe/common.js:

js 复制代码
// 1. 准备一个空数组,用来存放从后端拿到的数据
let users = [];

// 2. 向后端发起 HTTP 请求
fetch('http://localhost:3000/users')
    .then(data => data.json())    // 3. 把响应体转成 JSON 格式
    .then(data => {
        console.log(data);        // 4. 打印看看拿到了什么
        users = data;             // 5. 存到 users 数组中

        // 6. 在 DOM 树上找到表格的 tbody 节点
        const oBody = document.querySelector("#user-table tbody");

        // 7. 遍历数据,动态插入 HTML
        for (let user of users) {
            oBody.innerHTML += `
                <tr>
                    <td>1</td>
                    <td>${user.name}</td>
                    <td>${user.nickname}</td>
                    <td>${user.hometown}</td>
                </tr>
            `;
        }
    });

这段代码展示了完整的数据驱动页面流程:

  1. 后端 JSON 数据 →
  2. 前端 fetch 请求 →
  3. document.querySelector() 找到挂载点 →
  4. .innerHTML 动态修改 DOM 内容 →
  5. 浏览器自动重新渲染 →
  6. 用户看到最新数据

传统的静态页面是"后端返回什么,页面就显示什么",而这种动态方式让前端自己掌控渲染------拿到数据后,JS 操控 DOM 来更新页面,不需要刷新整个页面,这就是现代 Web 应用的基础模式。

补充:for...of 语法

代码中遍历用户数组用的是 ES6 的新循环:

js 复制代码
for (let user of users) {
    // user 就是当前遍历到的那个用户对象
}

老式写法需要手动计数:

js 复制代码
for (let i = 0; i < users.length; i++) {
    let user = users[i];
}

for...of 不需要计数器,可读性更好,是现代 JS 的推荐写法。

七、后端:用 json-server 快速搭建数据接口

从零初始化一个后端项目

进入 backend/ 目录,第一条命令:

bash 复制代码
npm init -y

这会生成 package.json,它是后端项目的身份证:

json 复制代码
{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "json-server --watch db.json"
  },
  "type": "commonjs",
  "dependencies": {
    "json-server": "^1.0.0-beta.15"
  }
}
  • name / version:项目名和版本号
  • scripts:定义启动命令,npm run dev 就是执行 json-server --watch db.json
  • dependencies:项目依赖了哪些第三方包,这里只有 json-server
  • type: "commonjs":使用 CommonJS 模块规范(Node.js 的传统方式)

安装 json-server

bash 复制代码
npm i json-server

json-server 是一个神器------它可以把一个 JSON 文件直接变成 HTTP 接口服务。对于学习阶段来说,不用学数据库、不用写 SQL、不用搭 Express,一个 JSON 文件就能跑起来。

数据文件 db.json

json 复制代码
{
    "users": [
        {
            "id": 1,
            "name": "张三",
            "hometown": "华夏",
            "nickname": "龙傲天"
        },
        {
            "id": 2,
            "name": "曹老板",
            "hometown": "梵蒂冈",
            "nickname": "梨花"
        },
        {
            "id": 3,
            "name": "niko",
            "hometown": "波黑尼亚",
            "nickname": "donk"
        }
    ]
}

一个普通的 JSON 对象字面量,users 数组里存放了三条用户记录,每条记录包含 id、name、hometown、nickname 四个字段。

json-server 会自动把这个结构映射为 RESTful 接口:

接口地址 方法 作用
http://localhost:3000/users GET 获取所有用户
http://localhost:3000/users/1 GET 获取 id=1 的用户
http://localhost:3000/users POST 新增一个用户
http://localhost:3000/users/1 DELETE 删除 id=1 的用户

零配置,直接能用------这就是 json-server 的价值。

启动后端服务

bash 复制代码
npm run dev

执行后,json-server 会监听 localhost:3000,前端就能通过 fetch 请求拿到数据了。--watch 参数表示它会监听 db.json 的文件变化,数据改了接口自动同步,开发体验极佳。

八、前后端联通:完整数据流一览

把整个过程串起来,数据是这样流动的:

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│  backend/db.json                                         │
│  { "users": [...] }                                      │
│       │                                                  │
│       ▼                                                  │
│  json-server --watch db.json                             │
│  启动 HTTP 服务 → http://localhost:3000/users             │
│       │                                                  │
│       │  HTTP 请求(前端 fetch)                           │
│       ▼                                                  │
│  fe/common.js                                            │
│  fetch('http://localhost:3000/users')                    │
│       │                                                  │
│       ▼                                                  │
│  data.json()  →  遍历数据  →  querySelector 找挂载点        │
│       │                                                  │
│       ▼                                                  │
│  innerHTML += 动态拼接 <tr> 标签                           │
│       │                                                  │
│       ▼                                                  │
│  浏览器重新渲染 → 用户看到表格中的用户数据                     │
└─────────────────────────────────────────────────────────┘

前后端通过 HTTP 接口 沟通,各管各的------前端不关心数据怎么存的,后端不关心页面怎么渲染。这就是前后端分离的核心思想。

九、总结

这个小项目虽然简单,但它涵盖了现代 Web 开发最重要的几个基础思维:

思想 具体体现
目录级分离 fe/ 管前端,backend/ 管后端,职责清晰
前端再分离 HTML 管结构、CSS 管样式、JS 管行为,三者各司其职
盒子布局思维 先规划盒子套盒子的层级关系,再填充内容
语义化思维 用 header/main/footer/aside 代替 div 满天飞
DOM 编程思维 理解 JS 如何在内存中操控页面元素树
接口通信思维 前端通过 fetch 请求后端 HTTP 接口,数据驱动页面

对于我来说,理解这些思想比记住具体代码重要得多。

相关推荐
脚本自动化开发6 小时前
存储涨价后,磐镭WO5迷你主机值得买吗
后端
一只爱撸猫的程序猿9 小时前
我看着一个 AI 引擎在 14 天里,从"记忆"走进了"搜索"
人工智能·后端·架构
LucianaiB9 小时前
【元宝搜索开发者征文大赛】AI时代,学得慢就不用学?用元宝搜索打造一个教程保质期,确保每一个教程符合你的现状
前端·人工智能·ai编程
excel9 小时前
JavaScript 对象池:减少高频对象创建与 GC 压力
前端
陈随易11 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员
卷无止境12 小时前
RAGFlow 项目全景报告:从文档解析引擎到 Agent 原生数据库
后端·python
小Z先生13 小时前
我用 Go + 系统 WebView 写了个纯本地 Postman:不装 Electron、不连云端
后端·github
子兮曰13 小时前
Chrome 权限元素实战:144 与 151 的渐进增强写法
前端·javascript·chrome
IT_陈寒13 小时前
Redis连接池泄漏那次,我差点把生产环境搞崩了
前端·人工智能·后端
强尼银手13 小时前
我花一天做了个格斗游戏原型,判定全对,然后被「美术」劝退了
前端·javascript