用 localStorage 存已投 ID、JSON 文件存计数,JS 拦截点击实现防重投与实时更新:页面加载时合并本地状态与远程数据,按钮点击后检查并更新 localStorage 与 UI。

如何用纯 HTML + 少量 JS 实现可持久化投票的 Feature Request 页面
不能只靠 form 提交就完事——用户刷新页面后投票状态丢失、重复提交无防制、选项计数不实时更新,是这类页面最常见的失效点。核心解法是:用 localStorage 存用户已投 ID,用静态 JSON 模拟后端计数,前端渲染时动态合并状态。
- 把每个需求项的
id(如"req-204")作为唯一键,存进localStorage,避免重复投票 - 计数数据放在一个
features.json文件里(可后续替换为 API),结构示例:{ "req-204": { "title": "支持 Dark Mode", "votes": 17 }, "req-205": { "title": "导出为 Markdown", "votes": 9 } } - 页面加载后先读
localStorage获取已投票 ID 列表,再 fetchfeatures.json,渲染时对每个项判断disabled状态和当前票数
为什么不用 submit 触发投票?
传统表单提交会刷新整个页面,导致体验断裂、状态重置。更合理的方式是监听按钮点击,调用 event.preventDefault() 阻止默认行为,再执行本地存储 + UI 更新。
- 每个投票按钮绑定
data-id="req-204",JS 通过dataset.id取值 - 点击后检查
localStorage.getItem('voted')是否包含该 ID;若已存在,直接return,不重复操作 - 新增投票时,用
JSON.parse(localStorage.getItem('voted') || '[]')读数组,.push(id)后再写回,确保原子性 - 别用
localStorage.setItem('voted', id)直接覆盖——这会清掉用户之前所有投票
localStorage 的兼容性与清理边界在哪
所有现代浏览器都支持 localStorage,但要注意它按协议+域名隔离,http:// 和 https:// 视为不同源;本地双击打开的 file:// 协议下多数浏览器会禁用 localStorage,开发时务必用 python3 -m http.server 或 VS Code Live Server 启服务。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
- 用户手动清除浏览器缓存时,
localStorage一并消失——这不是 bug,是预期行为,别试图绕过 - 单个域名下容量约 5–10MB,但实际建议控制在 10KB 内;存大量投票 ID 用逗号分隔字符串不如存 JSON 数组,后者可直接
JSON.parse复用 - 不要存敏感信息,
localStorage可被同域任意脚本读取,仅适合存公开、非认证类状态
响应式布局中投票按钮的视觉反馈怎么加才不突兀
用户点击后必须立刻看到变化,否则会反复点击。纯 CSS 可完成基础反馈,但需配合 JS 控制 class 切换。
立即学习“前端免费学习笔记(深入)”;
- 初始按钮用
class="vote-btn",投票后加class="voted",CSS 中定义.vote-btn.voted { opacity: 0.6; cursor: not-allowed; } - 别依赖
:active伪类——它只在按下瞬间生效,松手即消失,无法体现“已投”状态 - 计数数字建议用
<span class="vote-count" data-id="req-204">17</span>包裹,JS 投票成功后执行el.textContent = parseInt(el.textContent) + 1,比重新 innerHTML 整个卡片更轻量 - 如果需求项超过 20 条,记得加
loading骨架屏或最小高度占位,避免内容闪动
fetch("features.json") 404。要么把 JSON 放进 public/ 目录,要么改用内联 script 注入数据——复杂度随需求增长,但起点就该按这个思路搭。

















