Vue Router导航守卫中使用ElMessageBox的坑点与解决方案

17 阅读1分钟

问题背景

在Vue 3 + Vue Router项目中,我们经常需要在用户离开页面前进行确认,特别是当表单有未保存的更改时。onBeforeRouteLeave 与 Element Plus 的 ElMessageBox.confirm 结合使用是一个常见方案,但在实际应用中存在不少坑点。

直接上代码

onBeforeRouteLeave(async (to, from, next) => {
  if (!modelDirty.value) return next()
  try {
    await ElMessageBox.confirm('还未保存,离开会丢失,确定继续吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
      closeOnHashChange: false
    })
    modelDirty.value = false
    next()
  } catch (error) {
    next(false)
  }
})

坑点梳理

坑点1:next() 调用时机问题

问题描述:在异步操作中忘记调用 next(),或者重复调用

javascript

// ❌ 错误示例:可能在某些路径下未调用next
onBeforeRouteLeave(async (to, from, next) => {
  if (!dirty) {
    // 这里没有调用 next()!
    return
  }
  // ...其他逻辑
})

解决方案

// ✅ 正确示例:确保所有路径都调用next
onBeforeRouteLeave(async (to, from, next) => {
  if (!modelDirty.value) {
    next() // 确保这里也调用next
    return
  }
  // ...其他逻辑
})

坑点2:closeOnHashChange 设置的必要性

问题描述:用户点击浏览器前进/后退按钮时,hash变化可能导致MessageBox意外关闭

解决方案

// ✅ 必须设置 closeOnHashChange: false
await ElMessageBox.confirm('提示内容', '标题', {
  // ...其他配置
  closeOnHashChange: false, // 防止路由hash变化自动关闭
  closeOnClickModal: false, // 防止点击遮罩层关闭
  closeOnPressEscape: false // 防止ESC键关闭(可选)
})