纯html无法实现真正可用的投票工具,必须配合javascript处理交互、localstorage模拟本地存档(仅限演示)或后端服务支撑多人真实投票;直接写提交但无服务端接收等于投进黑洞。

纯 HTML 无法实现真正可用的投票工具,必须配合 JavaScript 处理交互、localStorage 模拟本地存档(仅限演示),或后端服务支撑多人真实投票。直接写 <form></form> 提交但没服务端接收,等于投进黑洞。
为什么 <input type="radio"> 是首选,而不是 <div> + <code>onclick
单选互斥、语义清晰、无障碍支持(屏幕阅读器能识别)、空格键可切换、移动端点击区域大——这些是 radio 原生能力。div 模拟需要手动管理 checked 状态、监听键盘、处理焦点、补 aria 属性,成本高且易出错。
关键实操点:
- 所有选项必须共用同一个
name,例如name="candidate",否则无法互斥 - 每个
input必须配<label for="xxx"></label>,for值与input的id一致,否则点击文字不生效 - 不要用
value="张三(2026年候选人)"这类含括号/空格的值,后端解析容易截断;建议用value="zhangsan"或value="c1"
localStorage 能存投票结果吗?能,但只对“自己”有效
它适合本地演示、教学、原型验证,比如你在 Chrome 里投了“选项A”,关掉再打开,还能显示“已投过”。但它不是数据库,也不是同步机制。
常见误用现象:
- 页面刷新后选项清空 → 没在
DOMContentLoaded里读localStorage.getItem('vote')并设checked - 点了好几次,“已投过”提示不出现 → 提交前没检查
if (localStorage.getItem('vote')) - 换 Firefox 打开,发现能再投一次 → 正确,因为 localStorage 是 per-browser 的,不是全局的
正确做法:提交前先读,有值就 alert("已投过") 或禁用按钮;加载时用 document.querySelector('input[value="' + saved + '"]').checked = true 恢复状态。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
表单提交不跳转?必须加 event.preventDefault()
哪怕你只是想本地记录,也别让浏览器走默认行为。默认 <button></button> 在 <form></form> 里就是 type="submit",一按就会刷新或跳转到 action 地址(如果写了的话)。
安全写法:
- 给
<form></form>绑定submit事件,第一行写event.preventDefault() - 或者干脆不用
<form></form>,改用<button type="button"></button>,避免任何默认行为干扰 - 不要用
onclick="submit()"直接调表单方法,它绕过事件监听,也触发不了preventDefault
示例片段:
document.getElementById('voteBtn').addEventListener('click', () => {<br> const selected = document.querySelector('input[name="choice"]:checked');<br> if (!selected) return;<br> localStorage.setItem('vote', selected.value);<br> alert('投票成功');<br>});
什么时候必须加后端?只要“不止你自己看”就必须加
如果你把页面发给同事、放 GitHub Pages、部署到公网,而希望所有人看到同一份实时票数,那 localStorage 完全失效。它不跨设备、不可信、不可审计。
最小可行后端只需三件事:
- 一个接收 POST 的接口(如
/vote),校验choice字段并写入文件或 SQLite - 一个返回统计的 GET 接口(如
/results),输出 JSON:{"A": 12, "B": 37, "total": 49} - 前端用
fetch('/vote', { method: 'POST', body: JSON.stringify({choice: 'B'}) })提交,别碰localStorage存结果
最容易被忽略的一点:前端 JS 里写的“投票成功”提示,和后端是否真写入成功,是两回事。没加 try/catch 和 response.ok 判断,用户点完以为投了,其实网络失败或服务挂了,票就丢了。










