angular18-自定义路由复用策略

78 阅读3分钟

在 Angular 中,{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy } 是用于 自定义路由复用策略 的配置。它的核心作用是 控制路由切换时是否复用组件实例,从而优化性能和用户体验。以下是详细说明:


1. 默认行为 vs 自定义复用策略

场景默认行为 (DefaultRouteReuseStrategy)自定义复用 (SimpleReuseStrategy)
路由跳转时总是销毁旧组件,创建新组件实例根据规则复用已有组件实例
组件生命周期每次跳转触发 ngOnDestroy 和 ngOnInit复用时不触发销毁和初始化
内存占用较低(无缓存)较高(缓存组件实例)
适用场景简单页面需要保持组件状态的复杂页面(如表格、编辑器)

2. 核心方法解释

自定义 SimpleReuseStrategy 需实现以下方法:

import { RouteReuseStrategy, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';

export class SimpleReuseStrategy implements RouteReuseStrategy {
  // 是否允许复用路由
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig; // 默认逻辑
  }

  // 是否允许缓存路由
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return true; // 所有路由都缓存(按需修改)
  }

  // 存储路由实例
  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
    // 缓存逻辑(如存入 Map)
  }

  // 是否允许恢复路由
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return true; // 总是尝试恢复(按需修改)
  }

  // 获取缓存的路由实例
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
    // 从缓存中获取
  }
}

3. 典型应用场景

场景 1:标签页切换保留状态

// 路由配置
{ path: 'user/:id', component: UserDetailComponent }

// 当用户从 /user/1 切换到 /user/2 时:
// - 默认行为:重新创建 UserDetailComponent,丢失之前的滚动位置、表单输入等
// - 使用复用策略:复用组件实例,仅更新数据

场景 2:复杂表格保留过滤条件

// 路由配置
{ path: 'report', component: ReportTableComponent }

// 用户从 /report 跳转到其他页面后返回:
// - 默认行为:重新加载表格,过滤条件重置
// - 使用复用策略:保持表格的过滤、分页状态

4. 完整配置步骤

步骤 1:创建自定义策略类

// simple-reuse-strategy.ts
import { RouteReuseStrategy, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';

export class SimpleReuseStrategy implements RouteReuseStrategy {
  private cacheRoutes = new Map<string, DetachedRouteHandle>();

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
  }

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    // 只缓存带有 cache=true 的路由
    return route.data['cache'] === true;
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    const path = this.getRoutePath(route);
    this.cacheRoutes.set(path, handle);
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    const path = this.getRoutePath(route);
    return this.cacheRoutes.has(path);
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
    const path = this.getRoutePath(route);
    return this.cacheRoutes.get(path) || null;
  }

  private getRoutePath(route: ActivatedRouteSnapshot): string {
    return route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/');
  }
}

步骤 2:注册到应用配置

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app/routes';
import { SimpleReuseStrategy } from './simple-reuse-strategy';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    { 
      provide: RouteReuseStrategy, 
      useClass: SimpleReuseStrategy // 替换默认策略
    }
  ]
};

步骤 3:在路由中标记需要缓存的页面

// routes.ts
const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    data: { cache: true } // ⭐ 标记此路由需要缓存
  }
];

5. 注意事项

问题解决方案
内存泄漏限制缓存数量,或提供手动清除缓存的方法
数据更新问题在复用组件中监听路由参数变化(如使用 ngOnInit 或 ActivatedRoute 参数订阅)
浏览器后退行为不一致在 shouldReuseRoute 中精细控制复用逻辑
动态路由缓存失效确保路由路径生成逻辑 (getRoutePath) 能唯一标识路由

6. 强制刷新缓存组件

当需要手动更新缓存时,可调用以下方法:

export class SimpleReuseStrategy {
  // 添加清除缓存方法
  clearCache(path: string): void {
    if (this.cacheRoutes.has(path)) {
      const handle = this.cacheRoutes.get(path)!;
      (handle as any).componentRef.destroy(); // 销毁组件
      this.cacheRoutes.delete(path);
    }
  }
}

// 在组件中调用
constructor(private reuseStrategy: SimpleReuseStrategy) {}

refresh(): void {
  this.reuseStrategy.clearCache('/dashboard');
  this.router.navigate(['/dashboard']);
}