浏览器禁用JS且无数据库时基于Node/Express实现待办应用方案
无前端JS、无数据库的Express待办清单实现方案
核心逻辑非常简单:你完全不需要前端JS操作DOM,靠原生HTML的表单默认提交能力+服务端动态渲染返回完整页面就能实现所有功能,这是Web开发早期最通用的多页应用模式,对入门者非常友好。
具体实现步骤
- 内存存储实现:不用数据库的话,直接在Express服务的全局作用域声明变量存数据就行,比如用数组存所有待办项,每条记录包含自增ID、待办内容、完成状态三个字段即可。注意这种存储方式在服务重启后数据会全部清空,面试时可以主动说明这个特性,证明你清楚方案的边界。
- 纯HTML实现所有交互:所有用户操作入口全部使用原生
<form>标签实现,不要绑定任何JS事件,完全靠浏览器原生的表单提交能力发请求:- 新增待办:写一个
method="POST"、action="/add"的表单,内部放name属性为content的文本输入框和提交按钮,用户点击提交时浏览器会自动把输入的内容打包发送到对应接口,全程不需要JS参与。 - 状态切换、删除操作:每个待办项对应两个独立的POST表单,action分别指向
/toggle/[待办ID]、/delete/[待办ID],提交按钮直接显示为「标记完成」「删除」即可,点击后浏览器会自动发请求到对应接口。
注意:不要引入任何前端JS逻辑,不要写fetch、XHR请求,不要操作DOM,只要浏览器支持基础HTML表单就能正常运行,哪怕完全禁用JS也不影响功能。
- 新增待办:写一个
- 服务端处理请求+返回页面:你已经掌握了静态HTML文件的分发,只要把静态返回改成动态拼接HTML即可,不需要引入复杂的前端框架或模板引擎,入门级写法就能跑通:
- 先写好固定的HTML骨架,包括页面头部、样式、新增待办的表单区域,这部分内容是固定不变的。
- 所有处理数据增删改的接口收到请求后,先操作内存里的待办数组完成对应的数据更新,之后直接返回302重定向到首页,不用在这些接口里重复写渲染逻辑。
- 首页的GET路由收到请求后,遍历最新的待办数组,把每条待办拼接成对应的HTML字符串(包含待办文本、两个操作按钮的表单),插入到固定骨架的列表位置,生成完整的HTML字符串后通过
res.send()返回给浏览器,浏览器会直接渲染最新的页面,用户看到的就是更新后的待办列表。
最小可运行核心代码示例
const express = require('express') const app = express() // 用Express自带中间件解析表单提交的数据 app.use(express.urlencoded({ extended: true })) // 内存存储,服务重启数据自动清空 let todos = [] let nextId = 1 // 首页路由,统一负责渲染最新的待办页面 app.get('/', (req, res) => { // 拼接待办列表HTML const todoListHtml = todos.map(todo => ` <li style="margin: 8px 0;"> <span style="${todo.done ? 'text-decoration: line-through; color: #999;' : ''}">${todo.content}</span> <form action="/toggle/${todo.id}" method="POST" style="display: inline; margin: 0 4px;"> <button type="submit">${todo.done ? '标记未完成' : '标记完成'}</button> </form> <form action="/delete/${todo.id}" method="POST" style="display: inline;"> <button type="submit">删除</button> </form> </li> `).join('') // 拼接完整HTML页面 const fullHtml = ` <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>无JS待办清单</title> <style> body { max-width: 600px; margin: 40px auto; padding: 0 20px; } ul { padding-left: 20px; } </style> </head> <body> <h1>待办清单</h1> <form action="/add" method="POST"> <input type="text" name="content" placeholder="输入待办内容" required style="width: 300px; padding: 4px;"> <button type="submit" style="padding: 4px 12px;">添加</button> </form> <ul>${todoListHtml}</ul> </body> </html> ` res.send(fullHtml) }) // 新增待办接口 app.post('/add', (req, res) => { const content = req.body.content?.trim() if (content) { todos.push({ id: nextId++, content, done: false }) } // 重定向回首页,避免表单重复提交 res.redirect('/') }) // 切换待办完成状态接口 app.post('/toggle/:id', (req, res) => { const id = Number(req.params.id) const targetTodo = todos.find(t => t.id === id) if (targetTodo) targetTodo.done = !targetTodo.done res.redirect('/') }) // 删除待办接口 app.post('/delete/:id', (req, res) => { const id = Number(req.params.id) todos = todos.filter(t => t.id !== id) res.redirect('/') }) app.listen(3000, () => { console.log('服务已启动,访问 http://localhost:3000 即可使用') })
上述代码里所有POST接口处理完数据都用res.redirect('/')跳回首页,是行业里通用的小技巧,既可以避免用户刷新页面时触发重复提交表单的浏览器提示,也能把所有渲染逻辑统一收口到首页路由,减少重复代码。如果觉得手动拼接HTML字符串太麻烦,可以在Express里配置ejs这类轻量模板引擎,直接在模板里循环遍历待办数据生成列表,代码会更整洁,同样不需要任何前端JS参与,学习成本很低。
内容的提问来源于stack exchange,提问作者badCoder
相关产品推荐
相关产品推荐

