Vue2 与 Vue3 路由钩子的区别及用法详解
一、核心区别概览
特性 | Vue2 (选项式API) | Vue3 (组合式API) |
---|---|---|
定义方式 | 组件选项形式 | 在setup()中调用函数形式 |
钩子名称 | beforeRouteEnter/Update/Leave | onBeforeRouteUpdate/Leave |
this访问 | beforeRouteEnter不能访问this | 无this概念,直接使用变量 |
异步处理 | next回调处理 | 支持async/await |
组合使用 | 难以复用 | 可轻松组合复用 |
二、Vue2 路由钩子详解
1. 三种组件内守卫
javascript
export default {
// 1.进入路由前调用(不能访问this)
beforeRouteEnter(to, from, next) {
next(vm => {
// 通过vm访问组件实例
})
},
// 2.路由变化但组件复用时调用
beforeRouteUpdate(to, from, next) {
// 可以访问this
if (to.params.id !== this.$route.params.id) {
this.fetchData()
}
next()
},
// 3.离开路由前调用
beforeRouteLeave(to, from, next) {
if (this.unsavedChanges) {
if (confirm('有未保存的更改!')) {
next()
} else {
next(false)
}
} else {
next()
}
}
}
2. 特点
- beforeRouteEnter 是唯一不能访问this的守卫
- 必须调用next()来解析钩子
- 全局守卫(beforeEach等)仍可用
三、Vue3 路由钩子详解
1. 组合式API守卫
javascript
import { onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router'
export default {
setup() {
const unsavedChanges = ref(false)
// 1.路由更新守卫
onBeforeRouteUpdate(async (to, from) => {
// 不需要next参数(除非需要重定向)
if (to.params.id !== from.params.id) {
await fetchData(to.params.id)
}
})
// 2.路由离开守卫
onBeforeRouteLeave((to, from) => {
if (unsavedChanges.value) {
return confirm('确定要离开吗?')
}
})
return { unsavedChanges }
}
}
2. 重大变化
-
更简单的API:
- 移除了next函数(除非需要重定向)
- 返回
false
取消导航,返回true
或undefined
继续导航 - 可以返回路由路径字符串或对象进行重定向
-
更好的TypeScript支持
-
组合复用示例:
javascript
// 可复用的路由守卫逻辑
function useRouteLeaveGuard(unsavedChanges) {
onBeforeRouteLeave(() => {
if (unsavedChanges.value) {
return confirm('确定离开?')
}
})
}
// 组件中使用
setup() {
const unsaved = ref(false)
useRouteLeaveGuard(unsaved)
// ...
}
四、迁移指南
从Vue2到Vue3的转换示例
Vue2版本:
javascript
beforeRouteLeave(to, from, next) {
if (this.unsavedChanges) {
next(confirm('离开吗?'))
} else {
next()
}
}
Vue3版本:
javascript
setup() {
const unsavedChanges = ref(false)
onBeforeRouteLeave(() => {
if (unsavedChanges.value) {
return confirm('离开吗?')
}
})
}
注意事项
-
beforeRouteEnter
在Vue3中没有直接对应物,需要改用其他方式:javascript// 替代方案:使用onMounted + 路由监听 setup() { const userData = ref(null) onMounted(async () => { userData.value = await fetchUser(route.params.id) }) watch( () => route.params.id, async (newId) => { userData.value = await fetchUser(newId) } ) }
-
全局守卫(beforeEach等)在Vue3中用法保持不变
五、最佳实践建议
-
Vue3推荐模式:
- 优先使用组合式函数封装可复用的路由逻辑
- 利用async/await处理异步操作
- 对于简单逻辑,直接返回布尔值而非使用next
-
复杂场景处理:
javascript
// 需要重定向的复杂场景
onBeforeRouteLeave((to, from) => {
if (needRedirect) {
return { path: '/login', query: { from: to.fullPath } }
}
if (unsavedChanges.value) {
return confirm('确定离开?')
}
})
- 组合多个守卫:
javascript
setup() {
// 可以注册多个同类型守卫
onBeforeRouteLeave(checkUnsavedChanges)
onBeforeRouteLeave(logRouteChange)
onBeforeRouteLeave(analyticsTracker)
}