Angular12自定义RouteReuseStrategy适配返回按钮、跨模块路由复用问题
路由复用策略配置合理性
RouteReuseStrategy是Angular路由器的全局生效策略,仅会使用根注入器中注册的实例,子模块中注册的策略不会生效。你当前在app.module.ts的全局注册配置是完全合理的,无需迁移到业务模块单独注册。
正确读取路由
areaCategory的方案 shouldReuseRoute方法会对路由树的每一层节点依次调用,你拿到的默认是最外层对应AppComponent的根路由节点,自然看不到子路由配置的data属性。你需要递归遍历ActivatedRouteSnapshot的firstChild属性,获取当前激活的最深层子路由节点,即可读取到你配置的areaCategory、reuseRoute等参数,工具方法示例:
// 递归获取最深层的激活路由快照 private getDeepestRoute(route: ActivatedRouteSnapshot): ActivatedRouteSnapshot { while (route.firstChild) { route = route.firstChild; } return route; }
shouldDetach、shouldAttach、retrieve等所有用到路由配置的方法,都需要先调用该方法拿到深层路由再读取data属性。
返回导航识别优化方案
当前onPopState设置的back标志位未及时重置,会导致后续所有导航都被识别为返回操作。你可以注入Router服务,监听NavigationEnd事件,每次导航完成后立即重置back标志位,确保该标志仅对本次返回导航生效:
constructor( private location: LocationStrategy, private router: Router ) { this.location.onPopState(() => { this.back = true; }); // 导航结束后重置返回标志位 this.router.events.subscribe(event => { if (event instanceof NavigationEnd) { // 跨模块跳转时清空缓存 const prevArea = this.getDeepestRoute(this.router.routerState.snapshot.root).data?.areaCategory; this.router.getCurrentNavigation()?.finalUrl?.root.children['primary'] && this.router.config.find(r => r.path === this.router.getCurrentNavigation().finalUrl.root.children['primary'].segments[0].path)?.data?.areaCategory; if (prevArea && currArea && prevArea !== currArea) { this.clearHandles(); } this.back = false; } }); }
现有代码优化点
- 缓存key优化:原有
getUrl仅用path作为key,不同模块如果存在同名path会出现缓存冲突,修改为拼接areaCategory前缀:
private getUrl(route: ActivatedRouteSnapshot): string { const deepRoute = this.getDeepestRoute(route); if (deepRoute.routeConfig) { const area = deepRoute.data?.areaCategory || 'common'; return `${area}:${deepRoute.routeConfig.path}`; } return Math.random().toString(); // 兜底避免undefined }
shouldReuseRoute逻辑优化:补充同模块详情页复用的判断:
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean { const futureDeep = this.getDeepestRoute(future); const currentDeep = this.getDeepestRoute(current); // 同模块、同路由配置时复用(满足同模块详情页跳转复用需求) if ( futureDeep.data?.areaCategory === currentDeep.data?.areaCategory && futureDeep.routeConfig === currentDeep.routeConfig ) { return true; } // 列表页仅返回时复用的规则 return this.back && !!futureDeep.data?.reuseRoute; }
- 滚动位置恢复:可以在列表组件的
OnDestroy生命周期中存储当前滚动位置,在组件ngOnInit时判断如果是复用状态则直接恢复滚动位置即可。
内容的提问来源于stack exchange,提问作者stackg91
相关产品推荐
相关产品推荐

