纯HTML表单无法存留言,需用localStorage配合JSON安全解析与防XSS动态渲染;删除功能须用data-id定位,首次加载和用户输入HTML是两大易忽略风险点。

纯HTML表单根本不能存留言,别双击就指望它工作
浏览器里直接打开 index.html,点提交按钮跳空白页或啥都不发生——这是正常现象。因为 <form> 本身只是语义容器,没有 JavaScript 阻止默认行为、没有存储逻辑,它连“提交”这个动作都只是触发页面跳转(比如 action="save.html" 就真去加载那个文件)。
常见翻车点:
• 写了 <form action="xxx"> 却没配后端,结果 404 或白屏
• 没加 onsubmit="return false;" 或没调 event.preventDefault()
• <textarea> 缺 id 或 name,JS 读不到值
• 用 <button type="button"> 而不是 <button type="submit">,导致回车无法触发
localStorage 是唯一能离线存留言的方案,但 null 判断必须写死
不用后端、不装服务、只靠浏览器就能持久化,localStorage 是唯一现实选择。但它不是“拿来即用”,第一次运行时 localStorage.getItem('messages') 返回 null,直接 JSON.parse(null) 就报 Unexpected token 'n'。
安全写法只有这一种模式:
• 先取值:const saved = localStorage.getItem('messages');
• 再判空:const messages = saved ? JSON.parse(saved) : [];
• 存的时候必须字符串:localStorage.setItem('messages', JSON.stringify(messages));
注意:隐身窗口默认禁用 localStorage,测试务必用普通窗口;单条留言超长(比如粘贴整篇论文)可能触发 QUOTA_EXCEEDED_ERR
动态渲染千万别用 innerHTML +=,否则删不了旧留言
用 document.getElementById('list').innerHTML += '<li>xxx</li>' 看似简单,实际会重绘整个 <ul>,所有已绑定的事件监听器(比如每条留言后的删除按钮)全部失效。更危险的是 XSS:<script>alert(1)</script> 这种输入会被直接执行。
正确做法是:
• 创建新元素:const li = document.createElement('li');
• 设内容(防 XSS):li.textContent = messageContent;
• 插入 DOM:document.getElementById('messageList').insertAdjacentElement('beforeend', li);
每条留言建议包在 <li class="message" data-timestamp="1722719520"> 里,方便后续加样式、排序或删除逻辑
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
删除功能要靠 data 属性定位,不能依赖 innerHTML 顺序
用户点击“删除”,你得知道删哪一条。如果靠 li 的索引位置(比如第 3 个 <li>),一旦中间某条被删,后续索引全乱;如果靠内容匹配,遇到重复留言就崩。
可靠方式是:
• 提交时给每条留言生成唯一标识,比如时间戳:li.dataset.id = Date.now().toString();
• 删除按钮绑定事件时,向上找最近的 li,读它的 dataset.id
• 从 messages 数组里用 findIndex 定位并 splice 删除,再重新写入 localStorage
别忘了删完 DOM 后同步更新数组,否则刷新页面又回来
立即学习“前端免费学习笔记(深入)”;
真实场景里,最易被忽略的不是怎么写,而是“首次加载时数据为空”和“用户输入含 HTML 标签”这两件事。前者导致解析失败,后者引发 XSS——它们不会报错,但会让留言板要么瘫痪,要么变成攻击入口。


















