需手动维护isDirty标志:页面加载时快照初始值,遍历form.elements按字段类型读取value/checked/selectedOptions,跳过disabled/readonly;监听input事件防抖设isDirty,提交成功后重置,beforeunload中同步返回提示。

怎么判断表单是否被用户改过
表单本身没有 isDirty 属性,浏览器不会自动记住“有没有动过”。你得自己记——而且必须在页面加载完成时立刻快照初始值,不能等用户操作后再开始记录。
- 遍历
form.elements,对每类字段用统一逻辑读取原始状态:input[type="text"]和textarea读value,input[type="checkbox"]读checked,select[multiple]读Array.from(el.selectedOptions).map(o => o.value) - 跳过
disabled或readonly字段,它们不属于用户可修改范围 - 别用
getAttribute('value')——它返回 HTML 属性值,不是当前 DOM 状态;也别只比el.value,因为 checkbox 的状态不在 value 里 - 空字符串
''、null、undefined在对比前建议统一转成字符串,避免松散相等误判
如何监听修改并防抖设置 dirty 标志
直接在每个 input 上设 isDirty = true 很危险:自动填充、日期选择器、富文本编辑器都会触发多次 input 事件,导致刚打开页面就变 dirty。
- 统一绑定
addEventListener('input', handler),不用change——后者要失焦才触发,太滞后 - 加
setTimeout防抖(比如 100ms),避免高频输入过程中反复设标志 - 对
contenteditable区域或第三方编辑器,需额外监听其内容变更事件(如editor.on('change')),再同步更新isDirty - 如果用了 React/Vue,确保快照值和真实 DOM 值一致——混用受控/非受控组件会导致快照失效
beforeunload 提示为什么没弹或总弹
现代浏览器(Chrome/Firefox)已禁用自定义提示文字,只显示统一文案:“离开此页面?您输入的数据可能未保存。”能否弹出,取决于你的 isDirty 判断是否准确且及时。
-
beforeunload必须同步返回值(哪怕只是e.preventDefault()),异步设置isDirty后再 return 无效 - 初始化时
let isDirty = false,别默认true,否则一打开就拦人 - 表单提交成功后必须重置
isDirty = false,否则用户填完关页还会被拦 - SPA 场景下,路由切换前要手动清理
beforeunload监听,否则重复绑定会触发多次提示 - 移动端 Safari 基本不支持
beforeunload,得降级用localStorage存草稿 + 页面可见性 API 检测切后台
为什么提交后关页还是提示未保存
常见原因是提交逻辑没真正“清空 dirty 状态”,或者提交成功回调没执行到重置语句。
立即学习“前端免费学习笔记(深入)”;
- 检查提交成功后的回调是否真被执行——网络请求失败、Promise 被 catch 吞掉、条件分支漏写都会导致
isDirty没重置 - 不要只靠
form.submit()触发原生提交,那会跳转页面,beforeunload不会生效;AJAX 提交后必须显式设isDirty = false - 如果用了
fetch或XMLHttpRequest,确保重置逻辑放在finally块里,而不是仅放在then中 - 注意表单里存在多个提交入口(按钮、回车、快捷键)——每个路径都要覆盖重置逻辑



















