formnovalidate仅对type="submit"按钮生效,需正确绑定表单且兼容性差,配合JavaScript手动处理提交与数据恢复才能可靠实现暂存功能。

formnovalidate 必须加在 type="submit" 按钮上才生效
它不是通用装饰属性,加错位置就彻底失效。常见错误是写在 <input type="text">、<button>(缺 type="submit")或表单外的按钮上——浏览器直接忽略该属性。
正确用法只有两种:
<button type="submit" formnovalidate>暂存</button><input type="submit" value="暂存" formnovalidate>
如果按钮在表单外部,必须用 form 属性显式绑定:<button type="submit" form="myForm" formnovalidate>暂存</button>。否则即使 DOM 看起来“靠近”,也不触发豁免逻辑。
formnovalidate 是单次提交豁免,不影响其他提交方式
它只跳过「这一次点击」触发的原生校验,不修改表单状态,也不影响其他交互路径。这意味着:
- 用户按回车提交,仍会触发完整校验(除非整个
<form>加了novalidate) - JS 调用
form.submit()会无视formnovalidate,必须改用form.requestSubmit() - 另一个没加
formnovalidate的<button type="submit">仍照常校验 -
:invalid伪类依旧生效——字段空着时边框可能还是红的,这不是 bug,是浏览器仍在计算 ValidityState
Safari 兼容性差,关键路径不能只靠 formnovalidate
iOS Safari ≤15.3 完全不支持;15.4+ 版本虽声明支持,但仍有概率触发 checkValidity() 并弹出原生提示框。一旦依赖它做“暂存”主流程,用户就会卡在红框里。
稳妥做法是双保险:
- 保留
formnovalidate作为 HTML 层标记 - 在 submit 事件中加
event.preventDefault(),再手动调用form.requestSubmit()或直接收集数据 - 对
<input type="file">这类特殊控件,不要尝试存它的value(永远为空或路径字符串),应跳过或单独处理 FileList
localStorage 存 draft 时别直接序列化 form 元素
localStorage.setItem('draft', document.querySelector('form')) 这种写法只会存入 [object HTMLFormElement],因为 form 对象不可 JSON 序列化。
正确提取逻辑要遍历 form.elements,并注意:
- 过滤掉
disabled和没有name属性的控件 - 区分
input[type="checkbox"]和[type="radio"]:取checked值,不是value -
select[multiple]需遍历selectedOptions提取所有选中项 - 用
JSON.stringify()存前,确保值都是基础类型(字符串、布尔、数字),避免循环引用
真正容易被忽略的是:表单恢复时,仅设置 input.value 不会触发 input 的 change 事件,UI 绑定(如 Vue/React 的响应式更新)可能不同步,得手动 dispatchEvent(new Event('change', { bubbles: true }))。

















