问题复现
ElementPlus:当点击返回或者地址栏回退时,MessageBox无效
<template>
<div>Element Plus Dialog 路由离开拦截测试</div>
<el-button type="primary" @click="$router.back()">返回</el-button>
</template>
<script setup lang="ts">
import { onBeforeRouteLeave } from 'vue-router';
import { ElMessageBox } from 'element-plus'
/** 路由拦截 */
onBeforeRouteLeave(async (to, from, next) => {
try {
await ElMessageBox.confirm(
'确定要离开吗',
{
cancelButtonText:'取消',
confirmButtonText:'确定',
type: 'warning',
}
)
next();
} catch (error) {
next(false);
}
});
</script>
Vant:当点击返回或者地址栏回退时,Dialog第一次生效,第二次开始无法生效
<template>
<div>Vant Plus Dialog 路由离开拦截测试</div>
<van-button type="primary" @click="$router.back()">返回</van-button>
</template>
<script setup lang="ts">
import { onBeforeRouteLeave } from "vue-router";
import { Dialog,Toast } from "vant";
/** 路由拦截 */
onBeforeRouteLeave(async (to, from, next) => {
try {
await Dialog.confirm({
message: "确定要离开吗",
confirmButtonColor: "#357ef7",
});
next();
} catch (error) {
next(false);
}
});
</script>
失效原因
Vant和ElementPlus的Dialog都有一个当路由地址变化时自动关闭的默认属性(官方文档中有说明)(ElementPlus是当hash变化的时候自动关闭),所以导致我们希望的是Dialog在路由变化的时候生效,但是Dialog在路由地址变化的时候自动小时了,产生了矛盾,所以失效
Vant
ElementPlus
Vant之所以第一次会生效,因为Vant在第一次的时候并未挂载到DOM节点中,导致默认的路由变化关闭Dialog不起作用,但是第二次开始Dialog已经挂载到DOM节点上了,默认路由关闭的属性也就生效了(Vant的Dialog第一次挂载之后不会移除,会通过display属性控制显示隐藏,ElementPlus的MessageBox会动态的挂载和移除,上述GIF的DOM中可以看出二者的差别)
解决方法
方案一:使用history模式
import {
createRouter,
createWebHistory,
createWebHashHistory,
RouteRecordRaw,
} from "vue-router";
const router = createRouter({
history: createWebHistory(),
// history: createWebHashHistory(),
routes,
});
方案二:关闭对应的路由变化自动关闭的属性
ElementPlus
/** 路由拦截 */
onBeforeRouteLeave(async (to, from, next) => {
try {
await ElMessageBox.confirm(
'确定要离开吗',
{
cancelButtonText:'取消',
confirmButtonText:'确定',
type: 'warning',
// 禁用路由变化自动关闭
closeOnHashChange:false
}
)
next();
} catch (error) {
next(false);
}
});
Vant
/** 路由拦截 */
onBeforeRouteLeave(async (to, from, next) => {
try {
await Dialog.confirm({
message: "确定要离开吗",
confirmButtonColor: "#357ef7",
// 禁用路由变化自动关闭
closeOnPopstate: false,
});
next();
} catch (error) {
next(false);
}
});
注意
上述的时效问题仅在hash模式的路由且并未关闭默认的路由变化自动关闭的属性时生效,history模式并不会失效