你是否也曾困惑前端和后端到底怎么分开又怎么协作今天我们就从 0 到 1手写一个用户信息列表页面。后端用json-server模拟 REST API前端用三件套HTML CSS JS实现动态渲染。整个过程会涉及到模块化思想、DOM 编程、fetch 异步请求、数组遍历……全是干货代码可直接运行。一、最终效果预览启动服务后访问index.html页面会从一个“假后端”http://localhost:3000/users拉取用户数据并动态展示在表格中ID姓名昵称家乡1lyg东理薛之谦南昌2hy航哥南昌3lqq橙帅信丰数据来源于db.json二、项目结构与设计思想我们采用前后端模块化分离的目录结构project/ ├── fe/ # 前端代码实际可独立部署 │ ├── index.html │ └── common.js └── backend/ # 后端模拟 ├── db.json └── package.json模块化的好处每个文件职责单一好维护前端只关心视图和交互后端只关心数据接口方便以后扩展比如把 json-server 换成真实后端三、后端准备用 json-server 搭建零代码 API1. 初始化项目进入backend目录执行npm init -y得到package.json项目描述文件。2. 安装 json-servernpm install json-server3. 创建数据库文件db.json写入以下内容对象字面量作为数据源{ users: [ { id: 1, name: lyg, hometown: 南昌, nickname: 东理薛之谦 }, { id: 2, name: hy, hometown: 南昌, nickname: 航哥 }, { id: 3, name: lqq, hometown: 信丰, nickname: 橙帅 } ] }4. 配置启动脚本在package.json中的scripts字段添加scripts: { dev: json-server --watch db.json }解析--watch表示监听文件变化自动重启服务。默认会开启http://localhost:3000并提供/users等 RESTful 接口。5. 启动后端npm run dev此时访问http://localhost:3000/users就能看到 JSON 格式的用户数据一个完整的后端就“假装”好了。四、前端页面HTML CSS 布局1. 整体结构语义化标签采用盒子模型思维先划分盒子区域再往里面填内容。使用 HTML5 语义标签让结构更清晰header用户管理系统/header main classcontainer aside侧边栏可留空/aside div classrow col-md-6 col-md-offset-3 table classtable table-striped thead.../thead tbody!-- 动态插入数据 --/tbody /table /div aside右侧栏可留空/aside /main footer© 2025 全栈小练习/footer2. 引入 Bootstrap 快速美化在head中加入 Bootstrap CDNTwitter 框架link hrefhttps://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css relstylesheet.container固定宽度居中PC 时代经典布局.row/.col-md-*栅格系统行列布局.table及.table-striped表格斑马纹样式注意表格必须包含tbody标签否则 JS 动态插入会找不到挂载点。完整index.html代码如下见文末汇总。五、DOM 编程与动态数据渲染1. 理解 DOM 树当浏览器解析 HTML 后会生成一棵文档对象模型DOM树document是整个文档的根对象document.documentElement对应htmldocument.body对应body每个标签都是一个节点Node可以查询、修改、添加、删除我们通过选择器找到表格的tbody节点然后动态往里面插入行。2. 使用 fetch 获取后端数据在common.js中编写fetch(http://localhost:3000/users) // 发起 GET 请求 .then(response response.json()) // 解析 JSON 流 .then(users { // 拿到用户数组开始渲染 })fetch是浏览器内置的 API用于异步 HTTP 请求它返回一个 Promise所以用.then()处理结果第一个.then()将原始响应转成 JSON 对象第二个.then()拿到真正的数据数组3. 动态生成表格行拿到users数组后遍历每一个用户对象构造tr并插入到tbody中。const tbody document.querySelector(.table tbody); // 找到挂载点 let i 1; for (let user of users) { tbody.innerHTML tr td${i}/td td${user.name}/td td${user.nickname}/td td${user.hometown}/td /tr ; i; }重点解析document.querySelector()返回第一个匹配 CSS 选择器的元素.innerHTML可以获取或设置元素内部的 HTML 结构我们使用追加内容模板字符串反引号...内部可以嵌入${变量}非常方便for...of是 ES6 引入的遍历数组的语法比传统for (let i0; iarr.length; i)更简洁、可读性更强为什么不直接用innerHTML 完整字符串而要用因为每次追加会保留原有的内容否则会覆盖掉之前的行本例中可接受但更推荐先构建好一个完整字符串再一次性赋值性能更好。4. 完整common.jsfetch(http://localhost:3000/users) .then(res res.json()) .then(users { const tbody document.querySelector(.table tbody); let i 1; for (let user of users) { tbody.innerHTML tr td${i}/td td${user.name}/td td${user.nickname}/td td${user.hometown}/td /tr ; i; } });六、完整代码清单1.backend/db.json{ users: [ { id: 1, name: lyg, hometown: 南昌, nickname: 东理薛之谦 }, { id: 2, name: hy, hometown: 南昌, nickname: 航哥 }, { id: 3, name: lqq, hometown: 信丰, nickname: 橙帅 } ] }2.backend/package.json{ name: backend, version: 1.0.0, description: 模拟后端API, main: index.js, scripts: { dev: json-server --watch db.json }, dependencies: { json-server: ^1.0.0-beta.15 } }3.fe/index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title用户列表 - 前后端分离演示/title link hrefhttps://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css relstylesheet /head body header classtext-center stylepadding: 20px; background: #f5f5f5; h1用户信息管理/h1 /header main classcontainer stylemargin-top: 30px; aside classcol-md-2 /aside div classcol-md-8 table classtable table-striped table-bordered thead tr thID/th th姓名/th th昵称/th th家乡/th /tr /thead tbody !-- JS 会动态填充数据 -- /tbody /table /div aside classcol-md-2 /aside /main footer classtext-center stylepadding: 15px; margin-top: 50px; background: #eee; © 2025 全栈练习 | 数据来自 json-server /footer script src./common.js/script /body /html4.fe/common.jsfetch(http://localhost:3000/users) .then(response response.json()) .then(users { const tbody document.querySelector(.table tbody); let index 1; for (let user of users) { tbody.innerHTML tr td${index}/td td${user.name}/td td${user.nickname}/td td${user.hometown}/td /tr ; index; } }) .catch(error console.error(数据加载失败, error));七、运行步骤在backend目录下执行npm run dev保持终端不关闭服务运行在3000端口用 Live Server 或直接打开fe/index.html注意直接打开文件会有跨域 json-server 默认支持 CORS可以直接用file://协议访问但更推荐用http-server或 Live Server 打开fe目录看到页面上的表格自动填充了数据库里的三条用户信息如果数据没显示打开浏览器控制台F12查看网络请求是否成功确认http://localhost:3000/users能否正常访问。八、知识点总结技术点说明模块化思想前端/后端代码分离各自独立开发、维护通过 HTTP 接口通信json-server用 JSON 文件快速搭建 REST API适合原型开发和学习语义化标签header, main, footer, aside 等让 HTML 结构更清晰SEO 友好DOM 树HTML 被解析成节点树document 对象提供查询和操作节点的方法fetch API现代浏览器内置的异步请求方法返回 Promise替代古老的 XMLHttpRequestinnerHTML动态修改元素内部 HTML 的快捷方式使用时注意 XSS 风险本例无用户输入for...of简洁遍历数组的方法直接获取每个元素的值无需手动维护索引模板字符串反引号 ${}语法轻松拼接字符串和变量九、拓展练习增加用户添加一个表单通过fetch POST向后端新增用户删除用户给每一行加一个删除按钮调用DELETE /users/{id}改用 async/await把.then()改成更现代的async/await写法错误处理在catch中显示友好的错误提示大厂面试尤其关注 DOM 编程、模块化以及底层 HTTP 交互 —— 这些基础打好了无论框架如何变化都能快速上手。写在最后这篇笔记来自我的全栈学习过程每一行代码都亲手敲过。前后端分离不是高大上的概念而是一种可以立刻实践的开发模式。希望这篇文章能帮你迈出“既懂前端又懂后端”的第一步。有任何疑问欢迎在评论区交流 如果你觉得有用请点赞 ❤️ 或收藏 ⭐让更多人看到~
前后端模块化分离实战:从零搭建用户列表展示(HTML+CSS+JS + json-server)
你是否也曾困惑前端和后端到底怎么分开又怎么协作今天我们就从 0 到 1手写一个用户信息列表页面。后端用json-server模拟 REST API前端用三件套HTML CSS JS实现动态渲染。整个过程会涉及到模块化思想、DOM 编程、fetch 异步请求、数组遍历……全是干货代码可直接运行。一、最终效果预览启动服务后访问index.html页面会从一个“假后端”http://localhost:3000/users拉取用户数据并动态展示在表格中ID姓名昵称家乡1lyg东理薛之谦南昌2hy航哥南昌3lqq橙帅信丰数据来源于db.json二、项目结构与设计思想我们采用前后端模块化分离的目录结构project/ ├── fe/ # 前端代码实际可独立部署 │ ├── index.html │ └── common.js └── backend/ # 后端模拟 ├── db.json └── package.json模块化的好处每个文件职责单一好维护前端只关心视图和交互后端只关心数据接口方便以后扩展比如把 json-server 换成真实后端三、后端准备用 json-server 搭建零代码 API1. 初始化项目进入backend目录执行npm init -y得到package.json项目描述文件。2. 安装 json-servernpm install json-server3. 创建数据库文件db.json写入以下内容对象字面量作为数据源{ users: [ { id: 1, name: lyg, hometown: 南昌, nickname: 东理薛之谦 }, { id: 2, name: hy, hometown: 南昌, nickname: 航哥 }, { id: 3, name: lqq, hometown: 信丰, nickname: 橙帅 } ] }4. 配置启动脚本在package.json中的scripts字段添加scripts: { dev: json-server --watch db.json }解析--watch表示监听文件变化自动重启服务。默认会开启http://localhost:3000并提供/users等 RESTful 接口。5. 启动后端npm run dev此时访问http://localhost:3000/users就能看到 JSON 格式的用户数据一个完整的后端就“假装”好了。四、前端页面HTML CSS 布局1. 整体结构语义化标签采用盒子模型思维先划分盒子区域再往里面填内容。使用 HTML5 语义标签让结构更清晰header用户管理系统/header main classcontainer aside侧边栏可留空/aside div classrow col-md-6 col-md-offset-3 table classtable table-striped thead.../thead tbody!-- 动态插入数据 --/tbody /table /div aside右侧栏可留空/aside /main footer© 2025 全栈小练习/footer2. 引入 Bootstrap 快速美化在head中加入 Bootstrap CDNTwitter 框架link hrefhttps://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css relstylesheet.container固定宽度居中PC 时代经典布局.row/.col-md-*栅格系统行列布局.table及.table-striped表格斑马纹样式注意表格必须包含tbody标签否则 JS 动态插入会找不到挂载点。完整index.html代码如下见文末汇总。五、DOM 编程与动态数据渲染1. 理解 DOM 树当浏览器解析 HTML 后会生成一棵文档对象模型DOM树document是整个文档的根对象document.documentElement对应htmldocument.body对应body每个标签都是一个节点Node可以查询、修改、添加、删除我们通过选择器找到表格的tbody节点然后动态往里面插入行。2. 使用 fetch 获取后端数据在common.js中编写fetch(http://localhost:3000/users) // 发起 GET 请求 .then(response response.json()) // 解析 JSON 流 .then(users { // 拿到用户数组开始渲染 })fetch是浏览器内置的 API用于异步 HTTP 请求它返回一个 Promise所以用.then()处理结果第一个.then()将原始响应转成 JSON 对象第二个.then()拿到真正的数据数组3. 动态生成表格行拿到users数组后遍历每一个用户对象构造tr并插入到tbody中。const tbody document.querySelector(.table tbody); // 找到挂载点 let i 1; for (let user of users) { tbody.innerHTML tr td${i}/td td${user.name}/td td${user.nickname}/td td${user.hometown}/td /tr ; i; }重点解析document.querySelector()返回第一个匹配 CSS 选择器的元素.innerHTML可以获取或设置元素内部的 HTML 结构我们使用追加内容模板字符串反引号...内部可以嵌入${变量}非常方便for...of是 ES6 引入的遍历数组的语法比传统for (let i0; iarr.length; i)更简洁、可读性更强为什么不直接用innerHTML 完整字符串而要用因为每次追加会保留原有的内容否则会覆盖掉之前的行本例中可接受但更推荐先构建好一个完整字符串再一次性赋值性能更好。4. 完整common.jsfetch(http://localhost:3000/users) .then(res res.json()) .then(users { const tbody document.querySelector(.table tbody); let i 1; for (let user of users) { tbody.innerHTML tr td${i}/td td${user.name}/td td${user.nickname}/td td${user.hometown}/td /tr ; i; } });六、完整代码清单1.backend/db.json{ users: [ { id: 1, name: lyg, hometown: 南昌, nickname: 东理薛之谦 }, { id: 2, name: hy, hometown: 南昌, nickname: 航哥 }, { id: 3, name: lqq, hometown: 信丰, nickname: 橙帅 } ] }2.backend/package.json{ name: backend, version: 1.0.0, description: 模拟后端API, main: index.js, scripts: { dev: json-server --watch db.json }, dependencies: { json-server: ^1.0.0-beta.15 } }3.fe/index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title用户列表 - 前后端分离演示/title link hrefhttps://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css relstylesheet /head body header classtext-center stylepadding: 20px; background: #f5f5f5; h1用户信息管理/h1 /header main classcontainer stylemargin-top: 30px; aside classcol-md-2 /aside div classcol-md-8 table classtable table-striped table-bordered thead tr thID/th th姓名/th th昵称/th th家乡/th /tr /thead tbody !-- JS 会动态填充数据 -- /tbody /table /div aside classcol-md-2 /aside /main footer classtext-center stylepadding: 15px; margin-top: 50px; background: #eee; © 2025 全栈练习 | 数据来自 json-server /footer script src./common.js/script /body /html4.fe/common.jsfetch(http://localhost:3000/users) .then(response response.json()) .then(users { const tbody document.querySelector(.table tbody); let index 1; for (let user of users) { tbody.innerHTML tr td${index}/td td${user.name}/td td${user.nickname}/td td${user.hometown}/td /tr ; index; } }) .catch(error console.error(数据加载失败, error));七、运行步骤在backend目录下执行npm run dev保持终端不关闭服务运行在3000端口用 Live Server 或直接打开fe/index.html注意直接打开文件会有跨域 json-server 默认支持 CORS可以直接用file://协议访问但更推荐用http-server或 Live Server 打开fe目录看到页面上的表格自动填充了数据库里的三条用户信息如果数据没显示打开浏览器控制台F12查看网络请求是否成功确认http://localhost:3000/users能否正常访问。八、知识点总结技术点说明模块化思想前端/后端代码分离各自独立开发、维护通过 HTTP 接口通信json-server用 JSON 文件快速搭建 REST API适合原型开发和学习语义化标签header, main, footer, aside 等让 HTML 结构更清晰SEO 友好DOM 树HTML 被解析成节点树document 对象提供查询和操作节点的方法fetch API现代浏览器内置的异步请求方法返回 Promise替代古老的 XMLHttpRequestinnerHTML动态修改元素内部 HTML 的快捷方式使用时注意 XSS 风险本例无用户输入for...of简洁遍历数组的方法直接获取每个元素的值无需手动维护索引模板字符串反引号 ${}语法轻松拼接字符串和变量九、拓展练习增加用户添加一个表单通过fetch POST向后端新增用户删除用户给每一行加一个删除按钮调用DELETE /users/{id}改用 async/await把.then()改成更现代的async/await写法错误处理在catch中显示友好的错误提示大厂面试尤其关注 DOM 编程、模块化以及底层 HTTP 交互 —— 这些基础打好了无论框架如何变化都能快速上手。写在最后这篇笔记来自我的全栈学习过程每一行代码都亲手敲过。前后端分离不是高大上的概念而是一种可以立刻实践的开发模式。希望这篇文章能帮你迈出“既懂前端又懂后端”的第一步。有任何疑问欢迎在评论区交流 如果你觉得有用请点赞 ❤️ 或收藏 ⭐让更多人看到~