[Vue]Tab关闭后,再次使用这个组件时,上次填写的内容依旧显示(路由复用导致组件实例未被销毁)
系统内使用了tab,当点击新增的时候,会打开一个tab,填写表单,点击取消,关闭tab。
再次点新增,发现之前填写的内容还在。
解决方案: <router-view /> 改为了<router-view :key="$route.fullPath" />
App.vue已经使用了 :key="$route.fullPath" 来强制重新渲染router-view。
内容由Claude Code生成
工作原理:
<router-view :key="$route.fullPath" />
- 每次路由变化(包括query参数变化)时,fullPath都会改变
- key变化后,Vue会销毁旧组件实例,创建新的组件实例
- 新实例的mounted()会重新执行,formData会重新初始化为空
优势
优势
┌──────────┬────────────────────────────────┐
│ 特性 │ 说明 │
├──────────┼────────────────────────────────┤
│ 代码改动 │ 仅1行修改 │
├──────────┼────────────────────────────────┤
│ 性能 │ 合理(仅在路由变化时销毁重建) │
├──────────┼────────────────────────────────┤
│ 维护性 │ 无额外维护成本 │
├──────────┼────────────────────────────────┤
│ 兼容性 │ Vue 2/3都支持 │
├──────────┼────────────────────────────────┤
│ 副作用 │ 无,这是官方推荐做法 │
└──────────┴────────────────────────────────┘
过程
问题所在:
- 路由path完全相同 - 只有query参数变化
- Vue Router的优化 - 在同一route path下,Vue会复用组件实例而不是销毁重建
- data()初始化只执行一次 - 组件首次创建时data()执行,之后复用组件时data()不会再执行
- formData数据被保留 - 表单数据保留了上次填写的内容
执行流程:
- ✅ 第一次打开:mounted() 执行 → formData 初始化为空 → 用户填写内容
- ❌ 第二次打开:由于路由path相同,组件复用 → mounted() 不执行 → formData 仍保留上次的数据
次要风险因素
- 缺少watch监听路由变化 - Form.vue中没有 watch: { '$route': ... } 来监听路由参数变化
- 缺少beforeRouteUpdate钩子 - 没有在路由守卫中重置表单
- formData引用问题 - 在add模式下,当组件复用时,formData对象的属性值被保留
有什么优雅的解决方案
● 这个问题有几个优雅的解决方案,我来逐一分析:
方案对比
1️⃣ 方案:路由key属性 ⭐⭐⭐⭐⭐(推荐)
最简洁优雅,0改动体积
在Layout或父组件中:
优点:
- 代码最简洁(只需1行)
- Vue官方推荐的标准做法
- 不同的fullPath自动销毁重建组件
- 完全隔离各个表单实例,无副作用
缺点:无
2️⃣ 方案:beforeRouteUpdate导航守卫 ⭐⭐⭐⭐
Vue Router标准模式,更灵活
在Form.vue的script中添加:
beforeRouteUpdate(to, from, next) {
// 路由变化时重置表单
if (to.path === from.path) {
this.resetForm();
}
next();
}
resetForm() {
this.formData = {
id: null,
projectCode: "",
projectName: "",
// ... 重置所有字段
};
this.$refs.projectForm?.clearValidate();
}
优点:
- 可以进行条件判断(仅当path相同时重置)
- 可以在重置前进行数据保存提示
- 符合Vue规范
缺点:
- 需要维护resetForm()方法
- 需要改动Form.vue逻辑
3️⃣ 方案:watch监听route ⭐⭐⭐
最直观易理解
watch: {
'$route.path'(newPath, oldPath) {
if (newPath === oldPath && this.mode === 'add') {
this.resetForm();
}
}
}
优点:
- 直观易懂,易于维护
- 可以监听特定的路由属性
缺点:
- 需要维护resetForm()方法
- 相比key属性,代码量多一些
4️⃣ 方案:在mounted前清空 ⭐⭐
有局限性
async mounted() {
// 新增模式下重置表单
if (this.mode === 'add') {
this.resetForm();
}
this.getMode();
// ...
}
缺点:
- 由于mounted可能不执行(路由复用),效果不稳定
- 不能从根本解决问题
🏆 最优雅的方案:路由key属性
原因:
- 这是Vue Router的官方设计模式
- 最简洁 - 只需1行代码
- 最高效 - 让框架自己管理生命周期
- 最灵活 - 可以对不同的路由应用不同的策略

浙公网安备 33010602011771号