徒手撸极简前后端分离Demo!吃透原生JS动态渲染底层

之前一直觉得前后端分离是个特别高大上的工程化概念,总以为得学一堆框架、接口规范、部署流程才能上手。

直到昨天我没用Vue、没用React,纯靠原生JS+HTML+CSS+json-server,手写了一套最朴素的前后端分离小案例,瞬间把底层逻辑彻底打通了。

没有花里胡哨的封装,所有流程都是最原始的写法,反而让我搞懂了框架背后到底在帮我们做什么。今天把我踩坑、试错、顿悟的全过程分享出来。

先说说我想解决的问题

以前写前端页面,所有数据都是写死在HTML里的。

展示一个用户表格,就得手动写一堆<tr>,新增、修改、删除数据都要改页面代码,特别笨拙,完全不符合实际开发逻辑。

我就想实现一个最基础的效果:数据单独存、前端动态拉取、自动渲染页面,真正做到数据和页面结构分离。

不想搭复杂的 Java、Python 后端,偶然发现 json-server 这个神器,零代码就能搭本地API接口,新手练手前后端分离再合适不过。

5分钟搭建极简模拟后端

说实话,以前总觉得后端搭建很麻烦,这次实操完才知道,本地练手的后端居然这么简单。

全程就三个文件,分工超级清晰,这也是我第一次真切体会到模块化拆分的意义。

1. 初始化项目配置

新建一个 backend 文件夹,执行 npm init -y 初始化项目,生成 package.json。这个文件就是项目的"身份证",记录所有依赖和启动脚本。

然后安装核心依赖 npm i json-server,最后配置启动命令,完整配置如下:

json 复制代码
{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev":"json-server --watch db.json" // 启动本地模拟接口服务
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs",
  "dependencies": {
    "json-server": "^1.0.0-beta.15"
  }
}

2. 搭建模拟数据库

新建 db.json,直接写入模拟用户数据,json-server 会自动把这个文件当成数据库,对外提供接口。

json 复制代码
{
  "users":[
    {
      "id": 1,
      "name": "张三",
      "hometown": "杭州",
      "nikename": "小三"
    }, 
    {
      "id": 2,
      "name": "李四",
      "hometown": "南昌",
      "nikename": "小四"
    },
    {
      "id": 3,
      "name": "王五",
      "hometown": "上海",
      "nikename": "小五"
    }
  ]
}

终端执行 npm run dev,直接启动服务,访问 http://localhost:3000/users 就能拿到所有用户数据。一行后端代码没写,接口直接可用,太适合新手练手了。

用Bootstrap重构页面,改掉Div满天飞的坏习惯

之前写页面,我清一色全用 div,堆得乱七八糟,自己回头看都看不懂结构。这次刻意用了 HTML5 语义化标签 + Bootstrap 栅格布局,彻底改掉了烂习惯。

语义化标签的真香之处

这次页面我用了 headermainasidefooter,表格也严格区分 theadtbody

以前觉得这些标签没用,和 div 没区别,后来才懂大厂为啥特别看重语义化:

  • 结构一目了然,哪个是头部、主体、侧边栏清晰分明
  • 搜索引擎抓取页面更友好,利于SEO
  • 表格拆分表头和表体,是规范开发的基础,后续DOM操作更精准

Bootstrap栅格布局快速适配页面

手动写CSS居中、自适应布局太麻烦,Bootstrap的栅格系统直接开箱即用。

我用了 container 做页面居中留白,row 定义行,col-md-6 col-md-offset-3 实现表格居中展示,几行类名搞定布局,不用写一行自定义CSS。

完整HTML页面代码:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<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>111</header>
    <!-- 核心主体区域 -->
    <main class="container">
        <aside>333</aside>
        <!-- 栅格布局:居中6列表格 -->
        <div class="row col-md-6 col-md-offset-3">
            <table class="table table-striped" id="user-table">
                <thead class="container">
                    <tr>
                        <td>ID</td>
                        <td>姓名</td>
                        <td>家乡</td>
                        <td>昵称</td>
                    </tr>
                </thead>
                <tbody>
                    <!-- JS动态渲染数据,这里留白 -->
                </tbody>
            </table>
        </div>
        <aside>444</aside>
    </main>
    <footer>222</footer>
    <!-- 引入自定义JS逻辑 -->
    <script src="./common.js"></script>
</body>
</html>

踩坑半小时!终于弄懂JS异步执行逻辑

这是本次学习最大的卡点,也是新手最容易犯的错!

我第一版代码写完,控制台能打印出接口数据,但页面空白、无任何渲染内容,当时直接懵了。

错误写法(千万别这么写)

我当时把数据遍历渲染的代码,写在了 fetch 请求的外面:

bash 复制代码
let users=[];

// 异步请求数据
fetch('http://localhost:3000/users')
    .then(data => data.json())
    .then(data => {
        console.log(data); // 控制台能正常打印数据
        users=data;
    })

// 同步遍历渲染(坑死我了!)
const oBody = document.querySelector('.table tbody'); 
for(let user of users){
    oBody.innerHTML += `
        <tr>
            <td>${user.id}</td>
            <td>${user.name}</td>
            <td>${user.nikename}</td>
            <td>${user.hometown}</td>
        </tr>
    ` 
}

我百思不得其解:数据明明拿到了,为啥渲染不出来?

后来翻了执行逻辑才恍然大悟:JS是单线程,同步代码优先执行,异步代码后置执行

页面加载后,会先执行外面的 for 循环,这时候 fetch 接口还在请求中,users 还是空数组。等接口请求成功、赋值完数据,页面早就渲染结束了。

执行步骤(按时间顺序)

  1. 定义空数组 users = []
  2. 发起 fetch 请求 → 丢到异步队列,不等待,继续走后面代码
  3. 立刻执行同步的 for 循环users 是空的,页面啥也不渲染
  4. 过了一会儿,网络请求成功 → 执行 .then → 给 users 赋值
  5. 但渲染代码早就跑完了! 页面永远不会更新

结果

  • 控制台能打印数据(赋值成功了)
  • 页面无任何数据(渲染时数据还没回来)

正确写法(所有依赖接口数据的操作,放进回调)

bash 复制代码
let users=[];
const oBody = document.querySelector('.table tbody'); 

// 异步获取数据 + 动态渲染,全部放在回调内部
fetch('http://localhost:3000/users')
    .then(data => data.json())
    .then(data => {
        console.log(data);
        users=data;
        // 数据回来后,再执行DOM渲染
        for(let user of users){
            oBody.innerHTML += `
            <tr>
                <td>${user.id}</td>
                <td>${user.name}</td>
                <td>${user.nikename}</td>
                <td>${user.hometown}</td>
            </tr>
        ` 
        }
})

执行步骤

  1. 定义变量、获取 DOM
  2. 发起 fetch 请求 → 丢到异步队列
  3. 等待网络请求......(期间不执行任何代码)
  4. 数据成功返回 → 执行 .then
  5. users 赋值 → 再执行 for 循环渲染
  6. 页面正常显示数据

结果

  • 控制台打印数据
  • 页面正常渲染所有用户信息

一句话总结

  • 第一段:不等数据回来,直接渲染 → 白跑一趟,没数据
  • 第二段:等数据回来,再渲染 → 逻辑正确,页面生效

这就是 JavaScript 异步编程最基础、最容易踩的坑!所有依赖异步数据的操作 (渲染 DOM、计算、判断等),必须写在异步回调(then/async-await)里面

新手核心避坑点:只要是接口请求、定时器这类异步操作,后续所有依赖返回结果的逻辑,必须写在异步回调里面!

原生DOM编程,吃透框架底层原理

现在的框架都帮我们封装好了DOM渲染,很多人只会用框架,根本不懂底层怎么实现的。这次纯原生手写,我彻底搞懂了动态渲染的本质。

简单说下我的通俗理解:

DOM 就是浏览器把所有HTML标签,转换成JS内存里的一棵树状对象 。我们通过 querySelector 精准选中页面节点,再用 innerHTML动态拼接HTML结构,把接口数据批量插入页面。

对比老式的索引for循环,ES6的 for...of 真的太香了,不用管下标、不用赋值,直接遍历数组元素,代码简洁可读性拉满,这也是现在主流的遍历写法。

最后聊聊模块化开发的感悟

以前写代码,所有结构、样式、逻辑全堆在一个文件里,看着简洁,实则一坨乱麻,后续根本没法维护扩展。

这次我严格做了拆分:

  • HTML:只负责页面结构,只管长什么样
  • CSS/外部Bootstrap:只负责页面样式,只管好不好看
  • 独立JS文件:只负责逻辑、数据请求、DOM渲染
  • json文件:只负责存储数据

这就是最基础的模块化思想:每个文件只做一件事,各司其职,解耦分离。所有大厂的工程化项目,底层都是这个逻辑。

收尾:本次学习3个核心收获

折腾完这个小demo,比我看十篇理论文章收获都大,总结三个最实用的知识点:

1.前后端分离的本质超简单:前端专注视图渲染,后端专注提供数据接口,数据和页面彻底解耦,这就是所有前后端项目的核心逻辑。

  1. JS异步执行是重中之重:同步先行、异步后置,所有依赖接口返回值的逻辑,绝对不能写在异步代码外部。

  2. 基础远比框架重要:Vue/React只是封装了DOM操作和异步逻辑,吃透原生DOM、异步机制、语义化开发,才算真正懂前端。

最后提一句:json-server 只适合新手练手 、本地调试,没有权限校验、数据持久化简陋,千万别用到线上正式项目

其实前端很多看似难懂的概念,亲手撸一遍demo就彻底通透了。你们初学前端的时候,有没有踩过JS异步、DOM渲染的坑?评论区聊聊~

相关推荐
光影少年15 小时前
react的 useReducer 使用场景、替代 useState 的情况
前端·react.js·掘金·金石计划
YAwu1115 小时前
原型与原型链:面试中的关键问题深入剖析
前端·javascript
HYCS15 小时前
用pixi.js实现fabric.js(四):StaticCanvas
前端·javascript·canvas
烬羽15 小时前
《读<JavaScript语言精粹>第3章,我整理了6个必须掌握的对象核心知识点》
前端
GuWenyue15 小时前
从零搭建用户管理系统!60分钟搞定RESTful接口+Bootstrap语义化首页
前端·后端
超人气王15 小时前
JavaScripts入门篇————js原型的底层原理
前端·javascript
蜡笔小电芯15 小时前
【Electron】第1章—新建工程(基于 Electron + Vite + JavaScript)
前端·javascript·electron
_xaboy15 小时前
开源Vue组件 FormCreate 使用组件内部方法校验
前端·vue.js·开源
审判长烧鸡15 小时前
【AI问答/前端】前端满天过海局(一)
前端·vue·浏览器