onBeforeRouteLeave 是 Vue 3 组合式 API 中推荐的页面级离开守卫,接收 (to, from) 参数,通过返回布尔值或 Promise 控制导航,支持逻辑复用、条件拦截与自定义 Hook 封装。

在 Vue 3 组合式 API 中,onBeforeRouteLeave 是实现页面级离开守卫的推荐方式,它比选项式 API 的 beforeRouteLeave 更轻量、更语义清晰,且天然支持逻辑复用与条件控制。
直接在 setup 中注册离开守卫
无需额外声明组件选项,直接在 setup() 或 onMounted 后调用即可。守卫函数接收三个参数:(to, from, next)(Vue Router 4.1+ 已弃用 next 回调,改用返回布尔值或 Promise)。
- 返回
false:取消导航,保持当前页面 - 返回
true或不返回:允许离开 - 返回 Promise(如调用确认弹窗):等待 resolve 后决定是否离开
示例:
import { onBeforeRouteLeave } from 'vue-router'
export default {
setup() {
const formData = ref({ title: '', content: '' })
const isDirty = computed(() => !isEqual(formData.value, initialData))
onBeforeRouteLeave((to, from) => {
if (isDirty.value) {
return window.confirm('有未保存的更改,确定要离开吗?')
}
})
return { formData }
}
}
配合状态管理做精细化控制
当表单状态分散在多个子组件或 store 中时,可在守卫中读取 pinia 或 ref 状态,避免手动维护“是否已修改”标志。
- 使用
useStore()获取 store 实例,检查hasUnsavedChanges等字段 - 监听多个响应式源(如
watchEffect+onBeforeRouteLeave联动) - 对特定路由目标放行(例如只拦截跳转到 /dashboard,不限制跳转到 /help)
示例(放行内部帮助页):
onBeforeRouteLeave((to) => {
if (isDirty.value && !to.path.startsWith('/help')) {
return confirmLeave()
}
})
封装可复用的自定义守卫 Hook
将通用逻辑抽离为 useRouteLeaveGuard,提升跨组件一致性:
- 接受判断函数(如
shouldBlock)和提示文案 - 内部自动处理 Promise 弹窗(如使用 Element Plus 的
ElMessageBox) - 支持动态启用/禁用(例如提交成功后调用
disable())
简易实现:
import { onBeforeRouteLeave } from 'vue-router'
import { ElMessageBox } from 'element-plus'
export function useRouteLeaveGuard(shouldBlock, message = '确认离开?') {
const unguard = onBeforeRouteLeave((to, from) => {
if (shouldBlock()) {
return ElMessageBox.confirm(message)
.then(() => true)
.catch(() => false)
}
})
return { disable: () => unguard() }
}
注意生命周期与作用域边界
onBeforeRouteLeave 仅在当前组件实例活跃时生效。需留意以下常见陷阱:
- 组件被
v-if移除时,守卫自动失效;若需全局守卫,应放在布局组件或 router 全局守卫中 - 异步 setup(
async setup())中调用需确保守卫注册时机早于路由解析完成 - 在
onUnmounted中无需手动清理 —— Vue Router 会自动解绑 - 服务端渲染(SSR)环境下该钩子不执行,需搭配客户端校验兜底
本质上,onBeforeRouteLeave 是组合式 API 对路由控制权的自然下放 —— 它让守卫逻辑紧贴数据源,减少耦合,也更容易测试和复用。只要把握好响应式依赖与导航控制的时机,就能写出既健壮又简洁的离开防护逻辑。

















