页面跳转时,登录状态几乎是绕不开的坎儿。比如进入个人信息页、下单页面,这些场景下,通常得先判断用户是否登录。如果已登录,直接跳转;没登录,就先拉到登录页,等登录成功后,再继续跳转。如果用户取消登录,那就终止。这种处理方式,看起来逻辑清晰,但实际用起来问题不少。
最大的麻烦在于:很多页面都需要登录状态,于是要在大量入口处塞入登录判断逻辑。就算封装成一个方法,调用方还是得关心登录是否成功,逻辑复杂度降不下来。更别提登录页先关掉,再打开新页面,切换动画也显得很突兀,体验上不太流畅。
那么,有没有更好的方案呢?先梳理一下期望的效果:我们的目标是跳转到目标页,至于目标页是否需要登录,最好由内部自己处理,外部调用时无感知。总结下来就是——页面跳转时,内部先判断状态,再做后续行为。而这,恰好是 Na vigation 拦截器擅长的事。
Na vigation拦截器的介绍与使用
Na vPathStack 提供了一个 setInterception 方法,用来设置页面跳转拦截回调。这个方法需要传一个 Na vigationInterception 对象,包含三个回调:willShow、didShow 和 modeChange。我们主要在 willShow 里做拦截处理——页面即将显示时,判断是否已登录,没登录就重定向到登录页,已登录则放行。
@Entry@ComponentV2struct Index { na v: Na vPathStack = new Na vPathStack() isLogin: boolean = false aboutToAppear(): void { this.na v.setInterception({ willShow: (from: Na vDestinationContext | Na vBar, to: Na vDestinationContext | Na vBar, operation: Na vigationOperation, isAnimated: boolean) => { if (typeof to === 'object') { if (isLogin) { AppRouter.popPage() AppRouter.jumpPage('login', undefined) } } } }) } build() { Na vigation(this.na v) .hideToolBar(true) .hideTitleBar(true) .height('100%') .width('100%') }}拦截器细节优化
如何判断是否需要进行拦截
拦截器里能拦截重定向,但一个关键问题是:哪些页面需要拦截?最简单的想法是弄个数组,把所有需要登录校验的页面放进去,跳转时判断目标页是否在数组中。思路没错,但还有更简单的实现方式。系统路由表里有一个 data 字段,可以在里面加一个标记,比如 needLogin。拦截器里先获取目标页的这个参数,所有需要登录的页面,都加上这个字段就行。以用户信息页为例:
{ "routerMap": [ { "name": "login", "pageSourceFile": "src/main/ets/pages/login/LoginPage.ets", "buildFunction": "loginBuilder" }, { "name": "user_info", "pageSourceFile": "src/main/ets/pages/user/UserInfoPage.ets", "buildFunction": "userInfoBuilder", "data": { "needLogin": "1" } } ]}拦截器中获取该字段的方式如下:
this.na v.setInterception({ willShow: (from: Na vDestinationContext | Na vBar, to: Na vDestinationContext | Na vBar, operation: Na vigationOperation, isAnimated: boolean) => { if (typeof to === 'object') { const data = (to as Na vDestinationContext).getConfigInRouteMap()?.data if (data !== undefined && (data as object)['needLogin'] === '1' && !AppConstant.hasLogin) { AppRouter.popPage() AppRouter.jumpPage(Pages.login, undefined) } } }})登录成功后如何获取目标页和页面参数
登录成功后,怎么知道要跳回哪个目标页,以及需要什么参数呢?很简单——跳转到登录页时,带上两个参数 targetPage 和 targetParam,分别表示目标页和参数。如果 targetPage 是 undefined,说明登录后没有后续操作;否则就跳转过去,并把参数带上。在拦截器里,可以通过 to.pathInfo.name 拿到目标页名称,通过 to.pathInfo.param 拿到目标页参数,然后塞给登录页的 targetPage 和 targetParam 就行。
使用拦截器这种方式,完全符合最初的设想:外部调用不用关心是否要校验登录,由拦截器内部处理。登录后直接跳转到目标页,没有页面切换的突兀感。而且是否需要判断登录,只需在路由表里加一个字段,非常方便。