beforeRouteLeave(Vue 2)或onBeforeRouteLeave(Vue 3)是实现页面离开前确认的核心守卫,需配合isDirty状态、深拷贝初始数据、异步弹窗及next()控制导航;还需叠加beforeunload事件覆盖刷新/关闭等场景。

在 Vue Router 中,组件内守卫 beforeRouteLeave(Vue 2)或 onBeforeRouteLeave(Vue 3 Composition API)是处理“离开确认”的首选方式——它只在当前组件即将被导航离开时触发,逻辑聚焦、无副作用,且能精准控制路由跳转流程。
判断是否需要弹窗的关键:跟踪表单修改状态
不能每次离开都弹窗,必须明确“什么算未保存”。推荐做法是用响应式变量记录编辑状态,并与初始值做比对:
- 组件初始化时(
onMounted或created),深拷贝原始表单数据作为快照(如initialForm = JSON.parse(JSON.stringify(formData.value))) - 监听所有可编辑字段变化(
@input、@change或v-model更新后),设置isDirty.value = true - 调用保存成功或重置表单后,同步设
isDirty.value = false - 避免用浅比较(如
===)或仅靠时间戳判断,否则对象嵌套变更会漏判
Vue 3 中正确注册 onBeforeRouteLeave
该守卫必须在组件 setup 阶段同步注册,不能包裹在条件语句、异步回调或事件处理器中,否则可能失效:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- 导入并调用:
import { onBeforeRouteLeave } from 'vue-router' - 在
setup()内直接使用:onBeforeRouteLeave((to, from, next) => { ... }) - 不要写成
return { onBeforeRouteLeave }—— 它不是响应式属性,而是生命周期注册函数 - 若需访问组件内响应式数据(如
isDirty),确保在闭包中能读取到最新值(推荐用ref或computed)
弹窗交互与导航控制的配合要点
原生 window.confirm 简单但体验差;推荐用 UI 库(如 Element Plus 的 ElMessageBox)实现可控弹窗,注意异步等待和导航回调的衔接:
立即学习“前端免费学习笔记(深入)”;
- 调用弹窗方法(如
ElMessageBox.confirm)返回 Promise,用await等待用户操作 - 用户点击“确定”后调用
next()放行;点击“取消”则调用next(false)阻止跳转 - 务必保证
next()只被调用一次,重复调用或遗漏都会导致导航卡死 - 如果弹窗前需执行异步保存(如草稿自动存),可在确认后先
await saveDraft(),再调用next()
补充:覆盖所有退出场景不能只靠路由守卫
onBeforeRouteLeave 只拦截路由跳转(如点击链接、router.push),对刷新、关闭标签页、地址栏输入等无效。要真正防丢数据,需叠加 beforeunload 事件:
- 当
isDirty.value === true时,用window.addEventListener('beforeunload', handler)绑定提示 - handler 中返回任意字符串(现代浏览器忽略内容,只显示统一提示),例如
return '您有未保存的更改,确定要离开吗?' - 在组件卸载(
onBeforeUnmount)或isDirty变为 false 时,记得移除监听,防止内存泄漏 - 注意:Chrome 95+ 对
beforeunload有策略限制(如Permissions-Policy: unload=()),生产环境需测试兼容性

















