NativeScript 8.4+Angular13返回导航重复加载前页面问题
问题描述
已升级至NativeScript 8.4搭配Angular 13,tns doctor检测无异常。使用命名路由出口map,根路由为带Mapbox地图的页面:
- 向前导航(同一出口从
map到nearby/:id)正常,新页面加载无问题 - 返回导航时,先短暂显示前页面,随后出现空白屏,接着页面重新加载,控制台显示
ngOnInit()再次执行,导致Mapbox地图重复加载甚至崩溃
返回导航代码:
if (this._routerExtensions.canGoBack) { this._routerExtensions.back({ relativeTo: this.route }); }
路由配置:
{ path: 'map', component: NSEmptyOutletComponent, loadChildren: () => import('../../../libs/xplat/nativescript/features/src/lib/pages/map').then(m => m.MapModule), outlet: 'map', canActivate: [AuthGuard] }, { path: 'nearby/:id', // component: NSEmptyOutletComponent, // 启用时返回导航失效 loadChildren: () => import('../../../libs/xplat/nativescript/features/src/lib/pages/nearby').then(m => m.NearbyModule), outlet: 'map', canActivate: [AuthGuard] }
该功能在NativeScript 8.2中正常,因需适配Android 11+文件下载升级至8.4,寻求返回导航异常的解决办法。
解决方案
1. 修正命名路由出口的返回导航参数
NativeScript 8.3+对命名路由的导航逻辑有调整,使用back()时需明确指定命名出口,避免默认行为触发页面重建。修改返回代码:
if (this._routerExtensions.canGoBack()) { this._routerExtensions.back({ relativeTo: this.route, outlets: { map: null } // 明确针对map出口执行返回操作 }); }
2. 统一路由配置中的NSEmptyOutletComponent
注释掉的NSEmptyOutletComponent是命名路由出口的标准配置,之前启用时返回失效大概率是参数配置问题,现在恢复该配置并确保所有命名路由出口的配置一致:
{ path: 'nearby/:id', component: NSEmptyOutletComponent, // 恢复该配置 loadChildren: () => import('../../../libs/xplat/nativescript/features/src/lib/pages/nearby').then(m => m.NearbyModule), outlet: 'map', canActivate: [AuthGuard] }
同时确保MapModule和NearbyModule内部的路由均使用RouterModule.forChild()定义子路由,避免路由层级冲突。
3. 自定义路由复用策略保留页面实例
NativeScript Angular 8.4对命名路由的复用策略有变更,可自定义策略强制保留指定出口的页面实例,避免返回时重建:
创建自定义复用策略类:
import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from '@angular/router'; export class CustomRouteReuseStrategy implements RouteReuseStrategy { private storedRoutes = new Map<string, DetachedRouteHandle>(); shouldDetach(route: ActivatedRouteSnapshot): boolean { // 仅针对map出口的路由启用复用 return route.outlet === 'map'; } store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { const key = `${route.outlet}-${route.pathFromRoot.map(r => r.url.join('/')).join('/')}`; this.storedRoutes.set(key, handle); } shouldAttach(route: ActivatedRouteSnapshot): boolean { const key = `${route.outlet}-${route.pathFromRoot.map(r => r.url.join('/')).join('/')}`; return this.storedRoutes.has(key); } retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null { const key = `${route.outlet}-${route.pathFromRoot.map(r => r.url.join('/')).join('/')}`; return this.storedRoutes.get(key) || null; } shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { return future.routeConfig === curr.routeConfig; } }
在app.module.ts中替换默认策略:
import { RouteReuseStrategy } from '@angular/router'; import { CustomRouteReuseStrategy } from './custom-route-reuse-strategy'; @NgModule({ // ...其他配置项 providers: [ { provide: RouteReuseStrategy, useClass: CustomRouteReuseStrategy } ] }) export class AppModule { }
4. 优化Mapbox地图的销毁逻辑
如果上述方案仍存在地图重复加载崩溃问题,在地图组件中手动控制实例销毁,避免内存泄漏:
import { Component, OnDestroy, OnInit } from '@angular/core'; import { MapboxMap } from '@nativescript/mapbox'; @Component({ selector: 'app-map', templateUrl: './map.component.html' }) export class MapComponent implements OnInit, OnDestroy { private mapInstance: MapboxMap; ngOnInit() { // 初始化地图时保存实例引用 this.mapInstance = // ...你的地图初始化代码 } ngOnDestroy() { if (this.mapInstance) { // 销毁地图实例,避免重复加载 this.mapInstance.destroy(); } } }
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

