Vue 3动态表单缓存采用分层策略:一、Tab或路由内切换用keep-alive保状态;二、刷新或关闭后用localStorage+watch防抖暂存;三、多页面/账号共享用Pinia按路由键隔离;四、移动端H5用v-storage-input指令细粒度控制。

Vue 3 中动态表单缓存未提交的输入数据,核心思路是“分层缓存”:页面级用 keep-alive 保状态,跨会话或刷新后用 localStorage + Pinia 或 watch 持久化。不是所有场景都该用同一种方式,关键看用户离开的类型(Tab 切走?路由跳转?关浏览器?)。
一、Tab 或路由内切换:用 keep-alive 保实时状态
适合多 Tab 面板、步骤式向导、详情页返回编辑等高频来回场景。组件实例不销毁,输入框值、滚动位置、校验状态、富文本内容全保留。
- 在布局中包裹
<router-view></router-view>或动态<component :is></component>,显式声明要缓存的组件名:<keep-alive :include="['FormEdit', 'OrderStep2', 'UserProfile']"><br> <router-view /><br></keep-alive>
- 避免缓存敏感页(如登录页、支付页),用
exclude排除::exclude="['LoginPage', 'PaymentConfirm']" - 配合
activated和deactivated做轻量控制:比如在deactivated中清掉防抖定时器,在activated中检查权限更新,但不重置表单数据
二、页面刷新或关闭后恢复:用 localStorage + watch 防抖暂存
适用于 H5 页面、后台管理表单等用户可能意外刷新或关页的场景。重点是“不干扰正常流程”,只在用户真实输入后才写入,且避免重复触发。
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
- 用
watch监听整个表单对象(如form),开启deep: true,搭配防抖(延迟 600ms):watch(form, () => { debounceSave() }, { deep: true }) - 保存前做基础过滤:跳过
null、undefined、全空字符串,防止污染缓存 - 读取时用
JSON.parse并包裹try...catch,解析失败则清空对应 key,避免字段变更导致白屏 - 设置标志位(如
isHydrated = ref(false)),恢复数据后在nextTick中设为true,让watch真正生效
三、多页面/多账号共享表单草稿:用 Pinia 统一管理 + 路由键隔离
当表单可能从不同入口进入(如列表页点击“新增”或“继续编辑”)、或需支持账号切换时,Pinia 比 localStorage 更可控。
立即学习“前端免费学习笔记(深入)”;
- 定义一个
formDraftStore,按业务维度建 key(如formDrafts[`${route.name}-${route.query.id || 'new'}]`) - 进入页面时,先查 store 是否有对应草稿;有则直接赋值,无则初始化空对象
- 提交成功后,立即调用
store.clearDraft(route.name, route.query.id),主动清理 - 提供“清空草稿”按钮,点击后重置表单并清除 store 对应项
- 对含身份证、银行卡字段的表单,可加判断逻辑:检测到敏感字段时自动降级为内存缓存(
ref),不写入持久化存储
四、移动端 H5 进阶方案:自定义指令 v-storage-input
适合字段多、结构深(如投保人数组、受益人嵌套)、且需细粒度控制每个输入框缓存行为的场景。
- 指令接收数组参数:
v-storage-input="['insured', 'name', item.name, index]',分别表示缓存 key、字段名、当前值、数组索引 - 内部自动处理数组增删:若
index存在,则操作localStorage['insured'][index].name;否则存为单对象 - 支持过期时间(如 5 小时),避免长期占用空间
- 比全局 watch 更轻量,不监听整个 form,只响应被标记的字段

















