v1.7.0 为守卫的
next()回调新增可选options参数,支持在重定向时显式指定导航方式(push / replace / relaunch),不再被原始导航方式绑定
前言
在 v1.7.0 之前,守卫中调用 next(location) 重定向时,跳转方式完全由"触发守卫的那次导航方法"决定:router.push 触发的守卫重定向时仍用 uni.navigateTo,router.replace 触发的则用 uni.redirectTo。
这意味着一个常见场景无法实现:无论用户是从 push 还是 replace 进入受保护页面,未登录时都希望用 replace 跳转登录页,避免登录页之后残留多余的历史页面。v1.7.0 解决了这一限制。
一、问题分析
旧版行为
守卫的 next() 回调签名是:
typescript
type NavigationGuardNext = (to?: RouteLocationRaw | false) => void
handleGuardResult 中重定向时直接透传原始 mode:
typescript
// router/index.ts(v1.6.3)
if (result.redirect) {
const redirectTarget = this.matcher.resolve(result.redirect)
return this.executeNavigation(redirectTarget, from, mode, redirectDepth + 1, ...)
// ^^^^ 原始 mode 被沿用
}
| 触发导航 | 重定向实际调用 |
|---|---|
router.push |
uni.navigateTo |
router.replace |
uni.redirectTo |
router.relaunch |
uni.reLaunch |
router.back |
落入 else 分支 → uni.reLaunch |
使用者在守卫内无法单独指定重定向方式。
二、新增能力
1. 扩展 next() 签名
typescript
type NavigationGuardNext = (
to?: RouteLocationRaw | false,
options?: NavigationGuardNextOptions
) => void
interface NavigationGuardNextOptions {
mode?: NavigationRedirectMode
}
type NavigationRedirectMode = 'push' | 'replace' | 'relaunch'
options.mode 仅在 next(location) 重定向时生效,对 next() 和 next(false) 无影响。
2. 重定向方式优先级
typescript
// router/index.ts(v1.7.0)
const redirectMode = result.mode ?? (mode === 'back' ? 'relaunch' : mode)
- 守卫指定优先 :
next(location, { mode: 'replace' })显式指定时使用replace - 未指定则沿用原始 :
next(location)时沿用触发守卫的原始导航方式(向后兼容) - back 回退 relaunch :原始导航为
back时,未指定mode则回退为relaunch(因back无法跳转到页面栈外目标,保持 v1.6.3 的实际语义)
三、使用示例
场景一:登录拦截统一用 replace
最典型的应用场景。无论用户从哪种导航方式进入受保护页面,未登录时都强制用 replace 跳转登录页,避免登录后返回时出现受保护页面的残留历史:
typescript
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth && !isLoggedIn()) {
// ✅ 强制 replace,登录页之后不会残留受保护页面的历史
next({ name: 'login', query: { redirect: to.fullPath } }, { mode: 'replace' })
} else {
next()
}
})
对比旧版:
typescript
// ❌ 旧版无法控制,重定向方式由触发守卫的导航决定
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth && !isLoggedIn()) {
next({ name: 'login', query: { redirect: to.fullPath } })
// 若用户通过 router.push 进入,重定向会用 navigateTo,登录页之后会残留受保护页面
} else {
next()
}
})
场景二:退出登录后重置页面栈
退出登录后通常希望清空整个页面栈再跳转登录页,避免用户通过返回键回到已退出登录的页面:
typescript
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth && !isLoggedIn()) {
// ✅ 强制 relaunch,关闭所有页面后打开登录页
next({ name: 'login' }, { mode: 'relaunch' })
} else {
next()
}
})
场景三:保持原有行为(向后兼容)
不传 options 时行为与 v1.6.3 完全一致,现有代码无需任何修改:
typescript
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth && !isLoggedIn()) {
next({ name: 'login', query: { redirect: to.fullPath } })
// 沿用原始导航方式,与 v1.6.3 行为一致
} else {
next()
}
})
四、mode 取值对照
| 值 | 对应方法 | uni API | 说明 |
|---|---|---|---|
'push' |
router.push() |
uni.navigateTo |
保留当前页面,跳转到新页面 |
'replace' |
router.replace() |
uni.redirectTo |
关闭当前页面,跳转到新页面 |
'relaunch' |
router.relaunch() |
uni.reLaunch |
关闭所有页面,打开新页面 |
::: tip 注意事项
- 重定向方式仅影响跳转 API 的选择,守卫链、动画、事件等行为保持一致
mode仅在next(location)重定向时生效,对next()和next(false)无影响- 重定向仍会触发新的导航流程(重新执行所有守卫),最大重定向深度仍为 10 次 :::
升级指南
v1.7.0 是完全向后兼容的新功能版本,无需修改任何现有代码即可升级。
行为变化
| 场景 | v1.6.3 及之前 | v1.7.0 |
|---|---|---|
next(location) |
沿用原始导航方式 | 沿用原始导航方式(无变化) |
next(location, { mode }) |
不支持 | 使用指定的 mode 重定向 |
back 触发的重定向 |
实际走 relaunch |
未指定 mode 时仍回退 relaunch(无变化) |
| 其他导航方式触发的重定向 | 沿用原始方式 | 未指定 mode 时沿用原始方式(无变化) |
新增类型导出
NavigationGuardNextOptions---next()回调的可选参数类型NavigationRedirectMode--- 重定向方式类型('push' | 'replace' | 'relaunch')