RouteReuseStrategy
abstract class RouteReuseStrategy {
// 判断是否复用路由
abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean
// 存储路由快照&组件当前实例对象
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void
// 判断是否允许还原路由对象及其子对象
abstract shouldAttach(route: ActivatedRouteSnapshot): boolean
// 获取实例对象,决定是否实例化还是使用缓存
abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null
// 判断路由是否允许复用
abstract shouldDetach(route: ActivatedRouteSnapshot): boolean
}
新建文件,block.service.ts
import {Injectable} from '@angular/core';
import {
ActivatedRouteSnapshot,
RouteReuseStrategy,
DetachedRouteHandle
} from '@angular/router'
@Injectable()
export class BlockService implements RouteReuseStrategy {
public handlers: { [key: string]: DetachedRouteHandle } = {};
//表示对路由允许复用
shouldDetach(route: ActivatedRouteSnapshot): boolean {
//默认对所有路由复用 可通过给路由配置项增加data: { keep: true }来进行选择性使用,代码如下
//如果是懒加载路由需要在生命组件的位置进行配置
if (!route.data.keep) {
return false;
}
return true;
}
//当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const path = route.routeConfig?.path
if (path) {
this.handlers[path] = handle;
}
}
//若path在缓存中有的都认为允许还原路由
shouldAttach(route: ActivatedRouteSnapshot): boolean {
if(route.routeConfig?.path){
return !!this.handlers[route.routeConfig?.path]
}
return false
}
// 从缓存中获取快照,若无则返回null
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle| null {
if (!route.routeConfig) return null;
//在loadChildren路径上通过修改自定义RouteReuseStrategy中的检索函数时从不检索分离的路由。
if (route.routeConfig.loadChildren) return null;
if(route.routeConfig?.path){
return this.handlers[route.routeConfig?.path];
}
return null
}
//进入路由触发,判断是否同一路由
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
return future.routeConfig === current.routeConfig;
}
}
block.service.ts配置,其对应的路由写法
{
path: 'home',
component:HomeComponent,
data:{
keep:true
}
}
但是这里存在问题,加入需要用到路由懒加载,对应子路由path值为空的情况,就无法在store钩子里面存路由快照
// 父路由
{
path: 'home',
loadChildren: () => import('@pages/home/home.module').then(m => m.HomeModule)
}
// 子路由
{
path:"",
component:HomeComponent,
data:{
keep:true
}
}
对block.service.ts重新加以改造,父路由path与子路由path拼接,拼接成唯一键值,再赋值 新建custom-route-reuse-strategy.service.ts
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
RouteReuseStrategy,
DetachedRouteHandle
} from '@angular/router';
const pathFunc = (currentPath:string | undefined ,parentPath:string | undefined ):string => {
let path = "";
if(parentPath !== null && parentPath !== undefined && currentPath !== null && currentPath !== undefined){
path = parentPath+currentPath;
}else if(currentPath !== null && currentPath !== undefined){
path = currentPath;
}
return path;
}
interface iCacheRouters {
snapshot: ActivatedRouteSnapshot
handle: DetachedRouteHandle
}
@Injectable()
export class CustomRouteReuseStrategyService implements RouteReuseStrategy {
public cacheRouters:{[key:string]:iCacheRouters} = {};
//表示对路由允许复用
shouldDetach(route: ActivatedRouteSnapshot): boolean {
//默认对所有路由复用 可通过给路由配置项增加data: { keep: true }来进行选择性使用,代码如下
//如果是懒加载路由需要在生命组件的位置进行配置
// {path: 'search', component: SearchComponent, data: {keep: true}},
if (!route.data.keep) {
return false;
}else{
return true;
}
}
//当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const currentPath = route.routeConfig?.path;
const parentPath = route.parent?.routeConfig?.path;
const path = pathFunc(currentPath,parentPath);
if (path) {
this.cacheRouters[path] = {
snapshot:route,
handle:handle
}
}
}
//若path在缓存中有的都认为允许还原路由
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const currentPath = route.routeConfig?.path;
const parentPath = route.parent?.routeConfig?.path;
const path = pathFunc(currentPath,parentPath);
if(path){
return !!this.cacheRouters[path]
}
return false
}
// 从缓存中获取快照,若无则返回null
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle| null {
const currentPath = route.routeConfig?.path;
const parentPath = route.parent?.routeConfig?.path;
const path = pathFunc(currentPath,parentPath);
if (!route.routeConfig) return null;
if (route.routeConfig.loadChildren) return null; //在loadChildren路径上通过修改自定义RouteReuseStrategy中的检索函数时从不检索分离的路由。
if(path){
return this.cacheRouters[path].handle;
}
return null
}
//进入路由触发,判断是否同一路由
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
return future.routeConfig === current.routeConfig;
}
}
但是根据业务场景需求,退出系统后,换另一个用户登陆,还保存原来的快照状态,那是不合理的,这时候按需订制路由策略
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const currentPath = route.routeConfig?.path;
const parentPath = route.parent?.routeConfig?.path;
const path = pathFunc(currentPath,parentPath);
if(path){
if(currentPath === 'login'){ // 在路由是login的时候清空缓存,login需要特殊判断
this.cacheRouters = {};
}
return !!this.cacheRouters[path]
}
return false
}
添加到app.module.ts
@NgModule({
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomRouteReuseStrategyService
} // 路由复用策略
]
})
待续,需要补充,类似管理的多标签效果,单独关闭页面删除快照的方法