应用路由事件用于从应用级别监听主页面路由的开始和完成,也可以在路由真正执行前重写目标页面。
它适合处理路由上报、全局状态重置、访问控制、无效入口页纠正和页面迁移等与“一次路由”相关的逻辑。如果逻辑只与单个页面的创建、显示或销毁有关,应优先使用对应的页面生命周期。
应用路由事件只作用于主页面路由。dialogPage 的打开、关闭以及随所属页面销毁,均不会触发本页 API。
| API | 说明 |
|---|---|
uni.onBeforeAppRoute | 监听路由执行前的事件 |
uni.offBeforeAppRoute | 取消监听路由执行前的事件 |
uni.onAppRoute | 监听路由成功后的事件 |
uni.offAppRoute | 取消监听路由成功后的事件 |
uni.rewriteRoute | 在路由执行前重写本次路由 |
一次成功路由的主要执行顺序如下:
发起路由
-> 解析路径并校验目标
-> onBeforeAppRoute
-> 执行路由逻辑
-> 目标页面 onShow
-> onAppRoute
-> 路由转场动画完成
新页面创建时,相关事件和页面生命周期的顺序为:
onBeforeAppRoute -> onLoad -> onShow -> onAppRoute
返回已有页面或切换到已存在的 tabBar 页面时,不会再次触发 onLoad,顺序为:
onBeforeAppRoute -> onShow -> onAppRoute
onBeforeAppRoute 在页面栈变化以及页面创建、销毁等实际副作用发生前触发。onAppRoute 在路由成功且目标页面的 onShow 执行后触发,不等待路由转场动画完成。
| 场景 | onBeforeAppRoute | onAppRoute | 可重写 |
|---|---|---|---|
| 应用启动并进入有效首页或二级页面 | 触发 | 路由成功后触发 | 是 |
| 应用直接启动到不存在的页面 | 触发,notFound 为 true;支付宝小程序固定为 false | 未重写时按缺页流程触发;支付宝小程序不触发 | 支持 rewriteRoute 的平台可重写 |
navigateTo、redirectTo、reLaunch 成功 | 触发 | 路由成功后触发 | 是 |
| 切换到其他 tabBar 页面 | 触发 | 路由成功后触发 | 是,且目标必须是 tabBar 页面 |
switchTab 到当前 tabBar 页面 | 不触发 | 不触发 | 否 |
navigateBack、系统返回、返回手势或 Web History 后退 | 触发 | 路由成功后触发 | 否 |
| 路由 API 参数错误或目标页面校验失败 | 不触发;支付宝小程序仍会触发,且 notFound 为 false | 不触发 | 否 |
onBeforeAppRoute 已触发,但路由随后取消或执行失败 | 已触发 | 不触发 | 仅可在同步回调阶段重写 |
| 应用从后台恢复,但主页面路由未变化 | 不触发 | 不触发 | 否 |
| dialogPage 打开、关闭或随所属页面销毁 | 不触发 | 不触发 | 否 |
监听器注册前已经发生的事件不会补发。如需监听或重写 appLaunch,应在 onLaunch 生命周期中或之前尽早注册监听器。
onBeforeAppRoute 和 onAppRoute 的公共事件参数含义如下:
| 属性 | 说明 |
|---|---|
path | 目标页面路径,不包含开头的 / |
query | 当前轮路由解析得到的页面参数 |
openType | 路由类型。发生重写时保持原路由类型不变 |
notFound | 当前目标页面是否不存在 |
routeEventId | 应用实例内唯一的路由事件标识 |
onAppRoute 还会提供 timeStamp,表示当前轮路由事件生成时的时间戳。
不同平台可能提供额外的事件字段。编写跨平台代码时,应只依赖本节列出的公共字段。
未发生重写时,同一次路由的 onBeforeAppRoute 与 onAppRoute 使用相同的 routeEventId。每次成功重写都会生成新的路由事件和新的 routeEventId,最终的 onAppRoute 使用最后一轮 onBeforeAppRoute 的 routeEventId。
正常调用路由 API 时,参数错误或目标页面不存在会直接失败。除支付宝小程序外,此类失败不会产生应用路由事件。notFound 主要用于应用直接启动到不存在页面等已经进入路由流程的场景。
openType | 路由来源 |
|---|---|
appLaunch | 应用首次启动;Web 直接访问首页或二级页面等入口路由 |
navigateTo | uni.navigateTo;Web History 前进;无法识别为其他类型的新增页面路由 |
navigateBack | uni.navigateBack;系统返回、返回手势;Web History 后退;小程序系统返回 |
redirectTo | uni.redirectTo |
reLaunch | uni.reLaunch |
switchTab | uni.switchTab;用户切换到其他 tabBar 页面 |
平台差异
rewriteRoute 要求基础库 3.8.0 及以上版本,并受微信客户端版本、运行平台和分包限制。微信开发者工具模拟器不支持 rewriteRoute,应在支持该能力的真机环境中验证。my.createRouteObserver 实现路由事件监听,并将支付宝的 back、tabClick 分别归一化为 navigateBack、switchTab。支付宝的前置事件不提供目标页面是否存在的信息,因此 onBeforeAppRoute 的 notFound 固定为 false。当路由 API 的目标页面不存在时,支付宝仍会触发 onBeforeAppRoute,但不会触发 onAppRoute;应用直接启动到不存在的页面时同样不会触发 onAppRoute。支付宝小程序暂不支持 rewriteRoute。监听应用路由成功后的事件。
| Web | 微信小程序 | 支付宝小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|---|
| 5.25 | 5.25 | 5.25 | 5.25 | 5.25 | 5.25 |
| 名称 | 类型 | 必填 | 兼容性 | 描述 |
|---|---|---|---|---|
| callback | (event: AppRouteEvent) => void | 是 | 应用路由事件回调 |
| 名称 | 类型 | 必备 | 兼容性 | 描述 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| path | string | 是 | 路由页面路径,不包含开头的斜杠 | ||||||||
| query | UTSJSONObject | 是 | 路由页面参数 | ||||||||
| openType | string | 是 | 应用路由类型。 | ||||||||
| |||||||||||
| notFound | boolean | 是 | 路由页面是否不存在。支付宝小程序不提供该信息,固定为 false | ||||||||
| timeStamp | number | 是 | 事件触发时的时间戳 | ||||||||
| routeEventId | string | 是 | 路由事件唯一标识 | ||||||||
| page | IAnyObject | 否 | 当前打开页面的相关配置 | ||||||||
| pipMode | string | 否 | 可选值: - 'min': 视频页面缩小为小窗; - 'max': 视频小窗还原为页面; | ||||||||
| |||||||||||
| renderer | string | 否 | 渲染引擎 可选值: - 'webview': Webview 渲染引擎; - 'skyline': Skyline 渲染引擎; - 'xr-frame': xr-frame 解决方案; | ||||||||
| |||||||||||
| webviewId | number | 否 | 当前页面 id | ||||||||
onAppRoute 只描述最终实际生效的路由。一次路由发生重写时,被替换的中间目标不会触发 onAppRoute,只有最终成功进入的页面触发一次。
监听器抛出的异常不会中断底层路由流程,但应在监听器内部妥善处理业务异常。
const appRouteCallback = (event : AppRouteEvent) => {
console.log(`路由完成:${event.openType} ${event.path}`)
console.log(`路由参数:${JSON.stringify(event.query)}`)
}
uni.onAppRoute(appRouteCallback)
// 不再监听时,传入注册时的同一个函数对象。
uni.offAppRoute(appRouteCallback)
取消监听应用路由事件。不传 callback 时移除全部监听器。
| Web | 微信小程序 | 支付宝小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|---|
| 5.25 | 5.25 | 5.25 | 5.25 | 5.25 | 5.25 |
| 名称 | 类型 | 必填 | 兼容性 |
|---|---|---|---|
| callback | (event: AppRouteEvent) => void | 否 |
| 名称 | 类型 | 必备 | 兼容性 | 描述 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| path | string | 是 | 路由页面路径,不包含开头的斜杠 | ||||||||
| query | UTSJSONObject | 是 | 路由页面参数 | ||||||||
| openType | string | 是 | 应用路由类型。 | ||||||||
| |||||||||||
| notFound | boolean | 是 | 路由页面是否不存在。支付宝小程序不提供该信息,固定为 false | ||||||||
| timeStamp | number | 是 | 事件触发时的时间戳 | ||||||||
| routeEventId | string | 是 | 路由事件唯一标识 | ||||||||
| page | IAnyObject | 否 | 当前打开页面的相关配置 | ||||||||
| pipMode | string | 否 | 可选值: - 'min': 视频页面缩小为小窗; - 'max': 视频小窗还原为页面; | ||||||||
| |||||||||||
| renderer | string | 否 | 渲染引擎 可选值: - 'webview': Webview 渲染引擎; - 'skyline': Skyline 渲染引擎; - 'xr-frame': xr-frame 解决方案; | ||||||||
| |||||||||||
| webviewId | number | 否 | 当前页面 id | ||||||||
传入监听函数时,只移除同一个函数对象对应的监听器;不传参数或传入 null 时,移除通过 onAppRoute 注册的全部监听器。
const callback1 = (event : AppRouteEvent) => {
console.log(event.path)
}
const callback2 = (event : AppRouteEvent) => {
console.log(event.openType)
}
uni.onAppRoute(callback1)
uni.onAppRoute(callback2)
// 只移除 callback1。
uni.offAppRoute(callback1)
// 移除全部 onAppRoute 监听器。
uni.offAppRoute()
onAppRoute 和 onBeforeAppRoute 的监听器相互独立,清空其中一类不会影响另一类。
监听应用路由发生前的事件。
| Web | 微信小程序 | 支付宝小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|---|
| 5.25 | 5.25 | 5.25 | 5.25 | 5.25 | 5.25 |
| 名称 | 类型 | 必填 | 兼容性 | 描述 |
|---|---|---|---|---|
| callback | (event: BeforeAppRouteEvent) => void | 是 | 应用路由前置事件回调 |
| 名称 | 类型 | 必备 | 兼容性 | 描述 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| path | string | 是 | 路由页面路径,不包含开头的斜杠 | ||||||||
| query | UTSJSONObject | 是 | 路由页面参数 | ||||||||
| openType | string | 是 | 应用路由类型。 | ||||||||
| |||||||||||
| notFound | boolean | 是 | 路由页面是否不存在。支付宝小程序不提供该信息,固定为 false | ||||||||
| routeEventId | string | 是 | 路由事件唯一标识 | ||||||||
| page | IAnyObject | 否 | 当前打开页面的相关配置 | ||||||||
| pipMode | string | 否 | 可选值: - 'min': 视频页面缩小为小窗; - 'max': 视频小窗还原为页面; | ||||||||
| |||||||||||
| renderer | string | 否 | 渲染引擎 可选值: - 'webview': Webview 渲染引擎; - 'skyline': Skyline 渲染引擎; - 'xr-frame': xr-frame 解决方案; | ||||||||
| |||||||||||
| webviewId | number | 否 | 当前页面 id | ||||||||
onBeforeAppRoute 回调同步执行。可以根据目标页面、路由参数和路由类型记录信息,也可以在该回调中同步调用 rewriteRoute。
const beforeAppRouteCallback = (event : BeforeAppRouteEvent) => {
console.log(`准备路由:${event.openType} ${event.path}`)
console.log(`路由参数:${JSON.stringify(event.query)}`)
}
// 如需处理 appLaunch,应在 App.uvue 的 onLaunch 中尽早注册。
onLaunch(() => {
uni.onBeforeAppRoute(beforeAppRouteCallback)
})
同一个 routeEventId 对应的 onBeforeAppRoute 最多触发一次。重写后的目标会作为新一轮路由再次触发 onBeforeAppRoute,并使用新的 routeEventId。
取消监听应用路由前置事件。不传 callback 时移除全部监听器。
| Web | 微信小程序 | 支付宝小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|---|
| 5.25 | 5.25 | 5.25 | 5.25 | 5.25 | 5.25 |
| 名称 | 类型 | 必填 | 兼容性 |
|---|---|---|---|
| callback | (event: BeforeAppRouteEvent) => void | 否 |
| 名称 | 类型 | 必备 | 兼容性 | 描述 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| path | string | 是 | 路由页面路径,不包含开头的斜杠 | ||||||||
| query | UTSJSONObject | 是 | 路由页面参数 | ||||||||
| openType | string | 是 | 应用路由类型。 | ||||||||
| |||||||||||
| notFound | boolean | 是 | 路由页面是否不存在。支付宝小程序不提供该信息,固定为 false | ||||||||
| routeEventId | string | 是 | 路由事件唯一标识 | ||||||||
| page | IAnyObject | 否 | 当前打开页面的相关配置 | ||||||||
| pipMode | string | 否 | 可选值: - 'min': 视频页面缩小为小窗; - 'max': 视频小窗还原为页面; | ||||||||
| |||||||||||
| renderer | string | 否 | 渲染引擎 可选值: - 'webview': Webview 渲染引擎; - 'skyline': Skyline 渲染引擎; - 'xr-frame': xr-frame 解决方案; | ||||||||
| |||||||||||
| webviewId | number | 否 | 当前页面 id | ||||||||
offBeforeAppRoute 的移除规则与 offAppRoute 相同:传入注册时的同一个函数对象,只移除该监听器;不传参数或传入 null,移除全部前置路由监听器。
const beforeAppRouteCallback = (event : BeforeAppRouteEvent) => {
console.log(event.path)
}
uni.onBeforeAppRoute(beforeAppRouteCallback)
uni.offBeforeAppRoute(beforeAppRouteCallback)
// 移除全部 onBeforeAppRoute 监听器。
uni.offBeforeAppRoute()
在应用路由前置事件回调中重写当前路由。
| Web | 微信小程序 | 支付宝小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|---|
| 5.25 | 5.25 | x | 5.25 | 5.25 | 5.25 |
| 名称 | 类型 | 必填 | 兼容性 | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| options | RewriteRouteOptions | 是 | |||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||
| 名称 | 类型 | 必备 | 兼容性 |
|---|---|---|---|
| errMsg | string | 是 |
| 名称 | 类型 | 必备 | 兼容性 | 描述 |
|---|---|---|---|---|
| errCode | number | 是 | 路由错误码 - 4: 框架内部异常 | |
| errSubject | string | 是 | 统一错误主题(模块)名称 | |
| data | any | 否 | 错误信息中包含的数据 | |
| cause | Error | 否 | 源错误信息,可以包含多个错误,详见SourceError | |
| errMsg | string | 是 |
| 名称 | 类型 | 必备 | 兼容性 |
|---|---|---|---|
| errMsg | string | 是 |
rewriteRoute 用于重写当前正在处理的路由事件,且不支持 Promise 风格调用。调用时需遵守以下规则:
onBeforeAppRoute 回调中同步调用。在回调外调用,或在回调中的异步任务内调用,都会失败。routeEventId 只允许成功重写一次。存在多个前置监听器时,首次重写成功后,同一轮的后续重写调用会失败。openType。navigateBack 路由不允许重写。switchTab 只能重写到 tabBar 页面,navigateTo 不能重写到 tabBar 页面。fail 返回失败信息。preserveQuery 默认为 false:
false 时,使用 url 中携带的参数。true 时,完整保留当前路由事件的参数,并丢弃 url 中携带的参数。例如,当前目标参数为 a=1,重写地址为 /pages/new/new?b=2。preserveQuery 为 false 时最终参数为 b=2;为 true 时最终参数为 a=1。
const beforeAppRouteCallback = (event : BeforeAppRouteEvent) => {
if (
event.openType == 'navigateTo' &&
event.path == 'pages/old/old'
) {
uni.rewriteRoute({
url: '/pages/new/new?from=rewrite',
preserveQuery: false,
success: (result) => {
console.log(result.errMsg)
},
fail: (error) => {
console.error(error.errMsg)
},
complete: (result) => {
console.log(result.errMsg)
}
})
}
}
uni.onBeforeAppRoute(beforeAppRouteCallback)
success 表示本次重写请求已被接受;fail 表示本次重写被拒绝;无论成功或失败都会调用 complete。
重写后的目标会作为新的路由事件重新触发 onBeforeAppRoute。因此,“同一个路由事件只允许成功重写一次”不表示一次用户跳转只能重写一次。
A -> onBeforeAppRoute(routeEventId=1) -> 重写到 B
B -> onBeforeAppRoute(routeEventId=2) -> 重写到 C
C -> onBeforeAppRoute(routeEventId=3) -> 执行路由
C -> onAppRoute(routeEventId=3)
业务代码应避免不同重写规则之间形成循环。
完整示例代码参考 hello uni-app x 应用路由事件示例。
| 名称 | 类型 | 必备 | 兼容性 | 描述 |
|---|---|---|---|---|
| errMsg | string | 是 | 错误信息 |