与vue不同的是,他的复用策略提供了很多方法。让你根据不同机场景定义不同策略.
- 添加onlyChildkeepAlive条件:当从详情页面返回主页时才复用主页页面
import {
RouteReuseStrategy,
DetachedRouteHandle,
ActivatedRouteSnapshot,
} from '@angular/router';
@Injectable({ providedIn: 'root' })
export class RouteStrategyService implements RouteReuseStrategy {
private cacheRouters: Map<string, DetachedRouteHandle> = new Map<
string,
DetachedRouteHandle
>();
private previousUrl = '';
public shouldReuseRoute(
future: ActivatedRouteSnapshot,
curr: ActivatedRouteSnapshot,
): boolean {
this.previousUrl = this.getFullRouteURL(curr) || '';
return (
future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params)
);
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return Boolean(route.data['keepAlive']);
}
public store(
route: ActivatedRouteSnapshot,
detachedTree: DetachedRouteHandle,
): void {
const url = this.getFullRouteURL(route);
this.cacheRouters.set(url, detachedTree);
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const url = this.getFullRouteURL(route);
if (Boolean(route.data['onlyChildkeepAlive'])) {
return this.previousUrl.includes(url) && this.cacheRouters.has(url);
} else {
return this.cacheRouters.has(url);
}
}
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
const url = this.getFullRouteURL(route);
if (Boolean(route.data['keepAlive']) && this.cacheRouters.has(url)) {
return this.cacheRouters.get(url);
} else {
return null;
}
}
private getFullRouteURL(route: ActivatedRouteSnapshot): string {
const { pathFromRoot } = route;
let fullRouteUrlPath: string[] = [];
pathFromRoot.forEach((item: ActivatedRouteSnapshot) => {
fullRouteUrlPath = fullRouteUrlPath.concat(this.getRouteUrlPath(item));
});
return `/${fullRouteUrlPath.join('/')}`;
}
private getRouteUrlPath(route: ActivatedRouteSnapshot): string[] {
return route.url.map((urlSegment) => urlSegment.path);
}
}
- 添加一个函数,在组件被缓存的时候调用(场景:执行一些清除组件的service或定时器等任务)?
- 使用canDeActive守卫,执行组件一个方法去清除组件的service或定时器等任务
import { CanDeactivateFn } from '@angular/router';
export const candeactivateGuard: CanDeactivateFn<unknown> =
(component, currentRoute, currentState, nextState) => {
(component as any)?.guardDestroy?.();
return true;
};
import { ProcessService } from '@app/service/process.service';
import { Subscription } from 'rxjs';
export class DomeComponent {
subscriptionEvent() {
this.subscription = this.processService.statusChanged.subscribe(
async (result) => {
console.log(result)
})
console.log(this.processService.statusChanged)
}
unsubscriptionEvent() {
this.subscription?.unsubscribe();
}
guardDestroy() {
this?.unsubscriptionEvent()
}
}
- 在缓存组件前,执行组件一个方法去清除组件的service或定时器等任务
export class RouteStrategyService implements RouteReuseStrategy {
public store(
route: ActivatedRouteSnapshot,
detachedTree: DetachedRouteHandle,
): void {
const url = this.getFullRouteURL(route);
(detachedTree as any)?.componentRef?.instance?.cacheCompDestroy?.();
this.cacheRouters.set(url, detachedTree);
}
}
import { ProcessService } from '@app/service/process.service';
import { Subscription } from 'rxjs';
export class DomeComponent {
subscriptionEvent() {
this.subscription = this.processService.statusChanged.subscribe(
async (result) => {
console.log(result)
})
console.log(this.processService.statusChanged)
}
unsubscriptionEvent() {
this.subscription?.unsubscribe();
}
cacheCompDestroy() {
this.unsubscriptionEvent()
console.log('cacheCompDestroy')
}
}
- 添加一个函数,当组件被激活时调用(场景:恢复被清除组件的service或定时器等任务)?
- 由于路由复用策略服务会被里面的接口函数会重复触发,所以不适合不适合在里面定义激活方法;那么CanActivate守卫就挺合适的。只要把路由复用服务定义注册在根注入器中就能在CanActivate守卫里面获取
import { inject } from '@angular/core';
import { CanActivateFn, RouteReuseStrategy } from '@angular/router';
export const canactivateGuard: CanActivateFn = (route, state) => {
const routeStrategyService = inject(RouteReuseStrategy);
const url = state.url.split('?')[0];
const exec = Boolean(route.data['keepAlive']) ||
(
Boolean(route.data['onlyChildkeepAlive'])
&&
routeStrategyService.globalPreviousUrl.includes(url)
)
if (exec) {
const cacheRouter = (routeStrategyService as any)['cacheRouters'].get(url);
const component = cacheRouter?.componentRef?.instance;
component?.guardCanActivate()
}
return true;
};
import { ProcessService } from '@app/service/process.service';
import { Subscription } from 'rxjs';
export class DomeComponent {
subscriptionEvent() {
this.subscription = this.processService.statusChanged.subscribe(
async (result) => {
console.log(result)
})
console.log(this.processService.statusChanged)
}
unsubscriptionEvent() {
this.subscription?.unsubscribe();
}
guardCanActivate() {
this.subscriptionEvent()
}
}
- 如何获取上一次路由?
- ‘路由复用策略服务’暴露出的接口会触发多次,不适合记录上一次路由,最好就是在app.component.ts中记录
export class RouteStrategyService implements RouteReuseStrategy {
public globalPreviousUrl = '';
}
import { RouteStrategyService } from '@app/service/route.strategy.service';
export class AppComponent implements OnInit {
ngOnInit(): void {
this.router.events.subscribe(ev => {
if (ev instanceof NavigationEnd) {
this.routeStrategyService.globalPreviousUrl = ev.url;
}
});
}
}
注册自定路由策略
import { NgModule } from '@angular/core';
import { RouterModule, RouteReuseStrategy, Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
import { RouteStrategyService } from './route.strategy.service';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
providers: [ { provide: RouteReuseStrategy, useClass: RouteStrategyService } ],
exports: [RouterModule]
})
export class AppRoutingModule { }