beforerouteleave 是 vue router 中组件级路由守卫,用于在离开当前路由前拦截导航并提示用户保存表单;需配合 isdirty 状态、深比较原始数据与当前表单、异步弹窗确认及手动跳转实现完整逻辑。

在 Vue Router 中,beforeRouteLeave 是专门用于监听当前路由即将离开时的导航守卫,非常适合实现“用户修改表单后未保存,退出前提示确认”的场景。它只在组件内部生效,无需全局配置,逻辑清晰、控制精准。
一、beforeRouteLeave 的基本用法
该守卫定义在组件的 setup 或 options API 中,接收三个参数:to(目标路由)、from(当前路由)、next(继续导航的回调)。注意:Vue 3 + Composition API 中需使用 onBeforeRouteLeave,不能直接写在 setup 返回对象里。
- Options API 写法:直接作为组件选项属性,函数内调用
next(false)可取消导航,next()或next(true)表示放行 - Composition API 写法:在
setup()中调用onBeforeRouteLeave((to, from, next) => { ... }),必须在组件实例创建阶段注册(不能放在异步回调或条件分支中)
二、判断是否需要弹窗确认的关键逻辑
单纯监听离开不够,重点在于“什么情况下才触发确认”。常见判断依据是:表单数据是否被修改但未提交。推荐做法是用一个响应式变量(如 isDirty)记录编辑状态,并在输入事件或 v-model 更新时设为 true。
- 初始化时通过
JSON.stringify(formData)保存原始值,后续对比当前值是否变化 - 避免直接用
===比较对象,应使用深比较或序列化字符串比对 - 提交成功或重置表单后,记得将
isDirty重置为 false
三、弹窗确认与导航控制的配合要点
浏览器原生 beforeunload 事件已受限(仅显示通用提示),所以必须依赖自定义弹窗 + 主动拦截导航。关键点是:弹窗为异步操作,而 next() 必须同步调用,因此要先 next(false) 阻止跳转,等用户选择后再手动触发跳转。
- 调用
next(false)立即中断当前导航,页面停留在当前路由 - 弹出
ElMessageBox或confirm()后,在then回调中调用router.push(to.fullPath)或router.back()实现跳转 - 若用户点击“取消”,不执行任何跳转,保持原页面
四、完整可运行示例(Vue 3 + Pinia + Element Plus)
假设有一个编辑用户信息的页面,使用 ref 存储表单数据和原始快照:
- 在
setup()开头定义originalData = ref(JSON.stringify(form)) - 用
watch(form, () => isDirty.value = true)监听变更 - 在
onBeforeRouteLeave中:若isDirty.value为 true,则弹窗;用户确认后调用router.push(to.path);否则不处理 - 提交成功后执行
isDirty.value = false和originalData.value = JSON.stringify(form)
这个方案轻量、可控、兼容 Vue 2/3,且不侵入路由全局逻辑,适合中后台表单类页面快速落地。









