一. 什么是路由复用? 为什么使用路由复用?
路由在执行过程中对组件无状态操作,即路由在离退时组件状态会一并删除,再次进入该页面会重新进入ngOnInit
中,大部分情况这样是合理的。
但是在移动端这边,一般都是有查询列表页,用户可以进行下拉触底加载更多数据,这时候,当用户点击某项进入详情页后,再次跳回列表页时,会发现列表页重新刷新了一遍,用户上次的访问滚动记录已经不在了…这时候肯定会被提出需求:记住用户上次滚动的位置,数据在跳页面后不能丢失!
这时候就需要利用angular提供的RouteReuseStrategy
路由复用策略,重新构建改组件。
二. RouteReuseStrategy
的重要概念
-
shouldDetach
是否允许复用路由 -
store
当路由离开时会触发,存储路由 -
shouldAttach
是否允许还原路由 -
retrieve
获取存储路由 -
shouldReuseRoute
进入路由触发,是否同一路由时复用路由
用一种白话文像是这样:把路由 /list
设置为允许复用(shouldDetach
),然后将路由快照存在 store
当中;当 shouldReuseRoute
成立时即:再次遇到 /list
路由后表示需要复用路由,先判断 shouldAttach
是否允许还原,最后从 retrieve
拿到路由快照并构建组件。
三. 举例来创建路由复用策略demo
- 新建simple-reuse-strategy.ts,路由复用策略默认对所有路由复用 可通过给路由配置项增加data: { keep: true }来进行选择性使用。
import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
export class SimpleReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {};
// 表示对路由允许复用
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
// 默认对所有路由不可复用 可通过给路由配置项增加data: { keep: true }来进行选择性使用,代码如下
// true为可服用路由
// false为不可复用路由
return route.data.keep ? true : false;
}
// 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
AppRoutingCache.handlers[route.routeConfig.path] = handle;
}
// 若path在缓存中有的都认为允许还原路由
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!route.routeConfig && !!AppRoutingCache.handlers[route.routeConfig.path];
}
// 从缓存中获取快照,若无则返回null
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null;
}
return AppRoutingCache.handlers[route.routeConfig.path];
}
// 进入路由触发,判断是否同一路由
public shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
return future.routeConfig === current.routeConfig;
}
}
- 将策略注册到模块当中:
// app.module.ts
import {RouteReuseStrategy, RouterModule, Routes} from '@angular/router';
import {SimpleReuseStrategy} from './simple-reuse-strategy';
providers: [
/*路由复用策略*/
{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy }
]
- 设置特定路由使用路由复用策略:keep:true
{
path: 'advanceSearch',
component: AdvanceSearchComponent,
canActivate: [BaiduStatisticsGuard],
data: {
title: '全国律师诚信信息公示平台',
keep: true
}
},
- 使用路由复用策略后,ngOnInit 的方法不会再执行,这个时候需要把 ngOnInit的方法写在NavigationEnd里
import { filter } from 'rxjs/operators';
import { Router, NavigationEnd } from '@angular/router';
constructor(
private route: ActivatedRoute,
private router: Router,
) {
this.route.queryParams.subscribe(param => {
...
});
}
// 获取上次页面滚动轴scrollTop距离,重新复位
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
if (event.url === '/advanceSearch') {
if (this.resultList) {
this.resultList.nativeElement.scrollTop = this.router['scrollTop'];
}
}
});
参考文档
https://segmentfault.com/a/1190000011430157
https://segmentfault.com/a/1190000014944087