表单提交前需调用 event.preventdefault() 阻止默认刷新,待 indexeddb 的 put() 或 add() 异步写入完成(onsuccess 或 promise resolve)后再跳转或提示;务必在 onupgradeneeded 中创建 objectstore,推荐用 put() 避免重复 key 错误,多字段应分 objectstore 存储。

表单提交前怎么把数据存进 IndexedDB
不能直接绑定 submit 事件后调用 add() 就完事——IndexedDB 是异步的,表单默认会刷新页面,存一半就丢了。得先 event.preventDefault() 阻止提交,等 add() 的 onsuccess 或 Promise resolve 后再手动跳转或提示。
常见错误现象:DOMException: The transaction was aborted, so the database has not been changed,基本就是没等写入完成就关了连接,或者事务自动超时了。
- 用
indexedDB.open()打开库时,必须在onupgradeneeded里创建objectStore,否则后续add()会报InvalidStateError - 存表单数据推荐用
put()而非add(),避免重复 key 导致ConstraintError(比如用时间戳当 key,但用户连点两次) - 如果表单字段多,别一股脑塞进一个对象;按业务拆成
form_data、user_meta等多个 objectStore,查起来快,也方便后期清理
怎么从 IndexedDB 读出数据填回表单
不能靠 document.getElementById().value = xxx 硬塞——表单控件类型不同,<select></select> 得设 selectedIndex,<input type="checkbox"> 得设 checked 属性,直接赋值无效。
使用场景:编辑已保存的草稿、离线续填、多端同步后的本地还原。
立即学习“前端免费学习笔记(深入)”;
- 读取用
get()比getAll()更准,尤其当你有明确 ID(比如表单 hash 或后端返回的draft_id)时 - 注意
get()返回的是 Promise(用idb.open().then(db => {...})链式调用),不是同步值;别在then外面直接操作 DOM - 日期字段(
<input type="date">)存的时候建议转成 ISO 字符串(new Date().toISOString().split('T')[0]),读出来直接赋值给.value就能渲染
IndexedDB 存表单数据有哪些兼容性坑
Safari 14.1+ 才支持 indexedDB.databases(),想枚举当前所有库?别试了,iOS Safari 直接不认这个 API。Chrome 和 Firefox 支持好些,但 Android WebView 版本混乱,低于 Chrome 60 的内核可能连 onsuccess 都不触发。
性能影响:单次写入超过 10MB 容易触发 QuotaExceededError;表单带 base64 图片的话,必须先压缩或转 blob 分块存,不能全塞进一个 value。
- 别依赖
indexedDB.deleteDatabase()清库——Safari 下它不触发onsuccess,但其实删掉了;得靠open()+onupgradeneeded重建来确认 - 移动端键盘弹起时,部分安卓 WebView 会暂停 JS 执行,导致事务卡住;建议加个 5 秒超时 fallback,失败就存 localStorage 兜底
- Firefox 私密模式下默认禁用 IndexedDB,
indexedDB.open()会直接进onerror,得提前 try/catch 并降级
表单和 IndexedDB 之间要不要加一层封装
要,但别造轮子。用 idb 这个轻量库(npm i idb),它把 callback 风格全转成 Promise,自动处理事务重试和版本升级,比原生少写 70% 模板代码。
不用它的话,自己封装至少得覆盖三件事:事务自动重开、keyPath 自动推导、错误统一映射成可读消息(比如把 AbortError 转成“保存中断,请重试”)。
-
idb的openDB()第二个参数是 version,升级时只改它,upgradeCallback里写迁移逻辑,比原生onupgradeneeded清晰得多 - 存表单时用
transaction.objectStore('forms').put(data, data.id || Date.now()),key 不传就自增,传了就覆盖,省得判断 - 别在封装里加自动同步服务器逻辑——离线优先场景下,同步该由业务层控制时机,不是 DB 层该管的事
最麻烦的其实是事务生命周期管理:一个表单可能跨多个 fieldset,用户切 tab 时你得决定是暂存局部、还是等全部验证通过再 commit。这个边界不划清,后面 debug 时连日志都对不上。











