# Routing events rewrite
From the base library {% version ('3.8.0') %}, Weixin Mini Program can change the target page path and parameters of a routing event before it is sent to the base library but before it is actually processed.This is somewhat similar to the effect of URL redirects in HTTP, but in order not to redirect*pages with existing **redirectToconfusion, we call this new feature route rewriting (Route rewrite) 。
To better understand this feature, you may need to understand the mechanics of routing events
# compatibility
Current support:
- WeChat Android Passenger 8.0.57 and above
- WeChat iOS Passenger 8.0.61 and above
More platform adaptation is underway.
In addition, there are some currently known issues , please note.
On incompatible client or base library versions, you can usewx.redirectTofor backward compatibility, referencing the code example in the following usage.
# Basic usage
For example, we can rewrite all routes that jump to page A to page B in such a way:
// Add listening before routing event processing
wx.onBeforeAppRoute(res => {
// 监听触发时,判断事件是否需要重写
if (res.path === '/pages/A/A') {
// 重写路由事件
wx.rewriteRoute({
url: '/pages/B/B',
success(res) {
console.info('Rewrite successfully from A to B')
},
fail(res) {
console.error('Rewrite failed, reason: ' + res.errMsg)
// 由于兼容性问题或场景不适用等原因重写失败,回退
wx.redirectTo({
url: '/pages/B/B',
complete: console.info
})
}
})
return
}
})
In this example, if there is a routing event that targets/ pages / A / A(e.g.navigateTo)Downstream to the repository,wx.onBeforeAppRoute]]The listening is triggered,wxf.rewriteRoute]]After the rewrite,navigateTo]] [[tag-4-END]] The target becomes/pages/B/B`。Eventually a B page will be instantiated and pressed onto the page stack.
# Call timing
In the above example, the routing rewrite interfacewx.rewriteRouteis executed in thewX.onBeforeAppRoutelistening.This is because a routing rewrite can only be sent to the repository under a routin event and before the routin event has been executed with any processing. In other words, if the routing event has already had a real impact (for example, when the route causes old pages to pop up and destroy or new pages to be rendered), then we can't rewrite the routing events.So there is currently and onlywx.onBeforeAppRoutea time when a routing event can be rewritten, and the routing rewrite must occur simultaneously and during this listening callback.Overriding outside the callback ofwx.onBeforeAppRouteor asynchronously within the callback causes the override to fail.
# Target restrictions
Because a routing rewrite changes the target path of an existing routing event and cannot change the event type of the event, a routin rewrite needs to ensure that the new target path and event type match after the rewrite.For example:switchTabmust be a TabBar page, so rewriting cannot rewrite theswitchtabevent to a non-TabBar page.
# Common use cases
The code snippet here only serves as a simple scene demonstration
- If the page you are looking for doesn't exist, go back to the home page.
wx.onBeforeAppRoute(res => { if (res.notFound) { wx.rewriteRoute({ url: '/pages/index/index?from-not-found=' + encodeURIComponent(res.path), }) } }) - 线下活动结束后,活动页面下线,用户扫描线下旧物料时引导到新活动页;或者线下物料中写错了路径 / 参数,小程序中进行兼容:
wx.onBeforeAppRoute(res => { if (res.path === '/pages/old-or-wrong/activity/page') { wx.rewriteRoute({ url: '/pages/new/activity/page', preserveQuery: true, }) } }) - 进入新任务页面时,判断用户是否有上次未完成的任务,继续处理:
wx.onBeforeAppRoute(res => { if (res.path === '/pages/task/new-task') { const unfinishedTaskId = globalStatus.unfinishedTaskId if (typeof unfinishedTaskId === 'string') { wx.rewriteRoute({ url: '/pages/task/perform-task?taskId=' + unfinishedTaskId, }) } } }) - 小程序从首页下拉冷启动时,读取 storage 中存储的不同用户身份(例如顾客与商家、学生与家长等),跳转到不同的首页
wx.onBeforeAppRoute(res => { if (res.openType === 'appLaunch') { const enterOptions = wx.getEnterOptionsSync() if (enterOptions.scene === 1089) { const userRole = wx.getStorageSync('user-role') if (userRole === 'customer') { wx.rewriteRoute({ url: '/pages/customer-index/index' }) } else if (userRole === 'merchant') { wx.rewriteRoute({ url: '/pages/merchant-index/index' }) } else { /* do nothing */ } } } })
# 对比页面重定向
从最终结果上来看,路由重写与页面重定向 redirectTo 都能达到类似的效果(例如在上面的例子中,最终结果都是新建了一个页面 B 的实例作为栈顶),但二者在执行原理和过程上仍有一定的差别。
页面重定向与原路由事件(例如上例中的 navigateTo)是按顺序排队执行,也就是在执行完页面 A 的渲染任务(例如准备页面渲染环境,实例化页面,处理页面栈逻辑压入页面,渲染页面,触发对应的生命周期等)之后,再处理 redirectTo;而路由重写会在原路由事件下发后处理,框架会直接执行页面 B 的渲染任务。在这个流程中,页面 A 没有被实际实例化或渲染过,因此只渲染了一次页面(redirectTo 实际渲染了两个页面),流程更快、更简单,也更能充分发挥 WebView 预加载 的效果。
当然,也不是所有的 redirectTo 都可以被替换为 rewriteRoute,例如需要由用户选择重定向目标或者从其他页面返回后重定向等情况;另一方面,rewriteRoute 作为一个新能力,并非所有的用户的运行环境都支持路由重写。开发者可以在适用 rewriteRoute 的场景和环境下使用 rewriteRoute,而如果场景不合适或者当前运行环境不支持,则回退使用 redirectTo 进行重定向。
# 常见问题
为什么我请求后台接口之后再执行
rewriteRoute会失败?目前小程序提供的网络请求接口都是异步接口,发起网络请求之后,JS 运行时会在等待服务器响应时执行其他任务。因此,请求后台并等待后台接口返回时,路由事件实际上已经被处理和执行了。
理论上,我们也可以使路由事件的处理和执行等待网络请求返回。在等待期间,由于路由事件尚未处理,用户会持续停留在上一个页面(页面跳转的情况下)或者看到白屏(小程序启动的情况下),而这段时间的长短取决于网络请求的耗时,从而可能导致用户操作打开或跳转后持续没有响应。为了回避这种情况导致的体验恶化,现阶段我们只处理同步进行的路由重写。
为什么
wx.rewriteRoute不像navigateTo一样可以直接调用,而是要放在监听的回调中?因为相比于
wx.navigateTo是一次路由请求,对应的navigateTo是一种路由事件类型,rewriteRoute实际上并不是一种路由类型,它的作用是对一次已经存在的路由事件进行一些操作。onBeforeAppRoute监听会在路由事件下发时触发,在这个回调中我们才能准确地对路由事件进行判断和处理。
# 常见失败及对应原因
not supported当前客户端平台或版本不支持路由重写能力
rewriteRoute is only allowed in a onBeforeAppRoute callback在不正确的时机调用
wx.rewriteRoute(见上方 调用时机)rewriteRoute can only be called once in a route event, this page hash been rewritten to "XXX"多次重写了同一个路由事件。每一个路由事件只能被重写一次,可以先计算好最终的目标路径再调用。如果确实需要进行连续的重写,应该等待重写后的路由事件重新触发
onBeforeAppRoute监听回调,再进行重写a "navigateBack" event is not allowed to be rewritten页面返回
navigateBack事件是不能被重写的(因为目标页面是已经存在的原有页面)rewriting a "XXX" event to to a non-tab page("YYY") is not allowedrewriting a "XXX" event to a tab page("YYY") is not allowed重写后的目标页面与路由事件类型不匹配(见上方 目标限制)
rewriting a route event that belongs to XXX is not allowed.小程序不能重写目标为插件页面的路由事件,反之插件也不能重写目标为小程序或其他插件的路由事件
# 已知问题
- 目前仅能将路由事件重写到同一分包中的页面,暂不能重写到其他分包的页面。这个问题将在后续的客户端版本中修复