html表单无原生自动保存,需js+localstorage实现草稿机制;自动填充则依赖浏览器对autocomplete语义值(如current-password、email)的识别,须严格符合whatwg规范,且name、type、form结构协同生效。

HTML 表单没有原生自动保存能力,所谓“自动保存”全是 JavaScript + localStorage 搭建的临时草稿机制;而“自动填充”是浏览器基于 autocomplete 语义提示做的预填行为,两者技术原理、触发时机、控制粒度完全不同,混用或互替必然出错。
自动保存靠 JS 主动落盘,不是浏览器功能
用户刷新页面后数据还在,不是浏览器记住了,而是你代码把 input.value 存进了 localStorage,再在 DOM 就绪后手动还原。关键点不在 HTML,而在 JS 的时机和策略:
- 监听
input事件(不是change),配合防抖(推荐 800ms),避免每敲一个字就写一次存储 - 只存非空值:
if (el.value.trim()) { ... },避免覆盖已有有效缓存 - 键名必须唯一且可追溯:建议用
form-${formId}-${el.name}或${location.pathname}-${el.id} - 恢复逻辑不能等
DOMContentLoaded,得等每个input元素真实挂载完成后再赋值,否则 React/Vue 的 hydration 会丢值 -
beforeunload回调里必须同步执行localStorage.setItem(),里面不能有await、fetch或自定义函数封装(可能含异步)
自动填充靠浏览器猜,不是你写了就填
autocomplete 是提示,不是指令。浏览器是否填、填什么、什么时候弹建议框,全由它自己决定。生效前提是三者同时满足:
-
autocomplete值必须严格符合 WHATWG 标准:比如密码字段登录页用current-password,注册页用new-password,写成password或my-pwd直接失效 -
name和type要协同:邮箱字段type="email"+autocomplete="email"才稳定;type="text"却设autocomplete="email",Chrome 可能无视 - 结构必须合规:字段必须包裹在
<form></form>内,不能是孤立input;且用户至少手动提交过一次该表单,浏览器才开始记录填充偏好 - 移动端尤其敏感:Safari 对
address-level2(市)支持弱,常需额外加name="city"辅助识别
密码字段的自动填充最不可控
现代浏览器基本忽略 autocomplete="off",尤其对 type="password"。真正有效的应对不是对抗,而是绕行:
- 不要用
name="password"——防止后端误收,改用name="fake_pwd"并服务端忽略 - 初始设
type="text",等用户focus后再切为password,让浏览器优先填那个“可见”的文本框 - 动态插入密码框:DOM 加载完再用 JS 创建
input,避开浏览器初始解析阶段 - 填充后样式被接管?必须用
input:-webkit-autofill+box-shadow: 0 0 0px 1000px #fff inset覆盖底色,且加-webkit-transition-delay: 99999s否则过渡失效
框架项目里最容易漏掉的三个断点
React/Vue 项目不是加个 useEffect 或 mounted 就能搞定。防丢失逻辑常在这些环节断裂:
- 受控组件中,保存逻辑必须放在
onChange或@update:modelValue回调里,不能只监听 state——state 更新可能被 batch,debounce 会错过中间值 - SPA 路由跳转(如从
/edit到/list)不触发beforeunload,必须监听路由离开钩子(如beforeRouteLeave或useBeforeUnload)主动保存 - 第三方富文本组件(如
tinymce)不抛input事件,得监听其自有事件(如text-change),否则内容永远不进 localStorage
真正麻烦的从来不是怎么存,而是怎么判断“用户此刻到底还想不想留着这些数据”——关标签页、F5 刷新、React 组件卸载、iframe 被移除,每种退出路径的检测方式都不同,且不能拖慢正常交互。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











