效果
1 新建路由守卫
在router文件下新建一个router-guard的文件
import router from '@/router';
// 路由守卫 在localStorage 中存一个dirty属性
router.beforeEach(async (to, _from, next) => {
const isDirty = localStorage.getItem('isFormDirty');
const tipRoutes = ["/conferenceData/index"] // 需要跳转的路由地址集合
const tipText = '您有未保存的更改,确定要离开吗?'
if (tipRoutes.include(_from.path) && isDirty && !confirm(tipText)) {
next(false); // 用户点击取消,阻止跳转
} else {
const isDirty = localStorage.removeItem('isFormDirty'); // 跳转之后移除这个标识
next(); // 允许跳转
}
});
2 main.ts 导入 router-guards
import './router/router-guards';
3 具体业务代码 - 监听表单数据
数据发生改变的时候, 设置 localStorage 中 isFormDirty 字段, 表示表单已被修改
watch(
() => state.createFrom,
() => {
localStorage.setItem('isFormDirty', 'true')
},
{ deep: true },
);
几个注意小点: ( 容易出bug的地方 )
-
进入页面时, 重置状态
onMounted(() => { // 进入页面重置状态 localStorage.removeItem('isFormDirty') })
-
表单提交成功之后, 可能也需要清空表单. 这个节点是否需要自行判断 是否清空 isFormDirty字段
-
因为清空表单, 也会触发watch, 需要在nextTick 后再清空 代码如下:
// 不这样写的话, 你的代码逻辑就是 提交成功 => 置空字段 => watch 检测你的置空 => 再次设置 isFormDirty 为 true. 导致设置失效 nextTick(() => { localStorage.removeItem('isFormDirty') })
-
如果离开提示, 你点击取消. 但是菜单高亮还是变成了你点的菜单. 你可能就需要在 菜单文件中写一个 route.afterEach 的钩子去处理你的菜单高亮问题
router.afterEach((to, from, failureReasons) => { // 如果有跳转原因, 则是取消跳转, 重置高亮菜单为之前的菜单 if (failureReasons) { selectedKeys.value = [from.path]; // selectedKeys 是菜单v-model对应的值, 使用的库是ant-Menu } })
如果你的已修改表单离开, 单单路由切换需要提示, 问题到这里就结束了
88
4 组件切换提示
如果你还有组件切换, 已经编辑的表单也需要提示的话, 可以继续往下看
我的业务情况, 是在一个tab下, 有三个form, 每个tab切换之前需要提示(表单存在改动),如下图
- 页面实现父组件内容 (精简版)
<template>
<!-- 这里放弃v-model:activeKey="state.activeTab" 的写法, 用change事件手动触发 -->
<a-tabs @change="tabChange" :activeKey="state.activeTab">
<a-tab-pane key="tab1" tab="标题1"></a-tab-pane>
<a-tab-pane key="tab2" tab="标题2"></a-tab-pane>
<a-tab-pane key="tab2" tab="标题3"></a-tab-pane>
</a-tabs>
<component :is="state.activeTab"/>
</template>
<script lang="ts">
const tabChange = async (val: string) => {
const isFormDirty = localStorage.getItem('isFormDirty')
// 通过 isFormDirty 字段判断表单是否修改, 给出对应的提示
if (!isFormDirty) {
state.activeTab = val
localStorage.removeItem('isFormDirty')
return
}
const prompt = confirm('您有未保存的更改,确定要离开吗?')
if (prompt) {
state.activeTab = val
localStorage.removeItem('isFormDirty')
}
}
</script>
-
至此, 已经编辑的表单, 组件之前的切换离开, 也会出现提示.