Angular RouteReuseStrategy 路由复用策略

Angular 路由复用策略:
       对于单页面应用来说,每次路由切换,都会销毁前面的组件,路由离退时组件状态也一并被删除,重新加载相应路由对应的组件,在绝大多数的场景下,这样的处理都是合理的,但是有时候我们也会有一些特殊的需求,需要返回上一个页面时,保留离开页面时的状态。
       需求场景应用比如某列表,用户查询了到某条数据后,点击到详情页面,但返回之后想要保持上次列表搜索的状态。比如手机端,浏览滑动到页面某一处之后,点击了详情跳转,滑动返回之前的页面,想要保留到滑动之前的浏览位置状态,这些场景都需要保留组件状态的需求。
       之前的路由执行后,会清除所有组件的状态,返回上个页面,就重新在加载组件。为了达成上述保留组件状态的需求,angular推出了路由复用策略。

       angular官方文档中提到了 RouteReuseStrategy,提供一种自定义复用已激活路由的方式保存快照。接口声明了5个方法,我们都称它为:路由复用策略,本质是解决不同路由页切换时组件数据不丢失问题。

shouldDetach()
确定是否应分离此路由(及其子树)以便以后复用**

/**
**param: route    ActivatedRouteSnapshot 包含与当前组件相关的路由的当前瞬间信息
**/
abstract shouldDetach(route: ActivatedRouteSnapshot): boolean

store()
存储分离的路由。

/**
**param: route	ActivatedRouteSnapshot 包含与当前组件相关的路由的当前瞬间信息
**param: handle	DetachedRouteHandle 已分离的路由树
**/
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void

shouldAttach()
确定是否应重新连接此路由(及其子树)

/**
**param: route    ActivatedRouteSnapshot 包含与当前组件相关的路由的当前瞬间信息
**/
shouldAttach(route: ActivatedRouteSnapshot): boolean

retrieve()
检索以前存储的路由

/**
**param: route    ActivatedRouteSnapshot 包含与当前组件相关的路由的当前瞬间信息
**/
//返回值 DetachedRouteHandle 表示已分离的路由树。
abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null

shouldReuseRoute()
确定是否应复用路由 当将来的路由配置和当前的路由配置相同时,此策略将返回 true

/**
**param: future 将要离开的路由   ActivatedRouteSnapshot 包含与当前组件相关的路由的当前瞬间信息
**param: curr 将要加载的路由    ActivatedRouteSnapshot 包含与当前组件相关的路由的当前瞬间信息
**/

//每次切换路由时都会被调用
abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean

这些方法实现路由复用的流程如下图所示
在这里插入图片描述

我们要实现路由复用,需要自定义来实现这个类。在切换路由时,若符合路由复用的条件则将路由的快照存放起来,下次再打开此路由时加载对应快照。

1.首先,我们先要新建一个自定义路由复用的ts文件来实现接口RouteReuseStrategy。

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

export class ReuseStrategy implements RouteReuseStrategy {
  /*
   * @帮助理解
   * 假设访问了路由 xxx/a 该路由是设置为允许复用(shouldDetach)
   * xxx/a 存入在 store 中
   * shouldReuseRoute 命中, 当再次访问 xxx/a 时, 则该路由是要复用的路由
   * 判断 shouldAttach 是否还原, 可以从 retrieve 中拿到路由快照, 重新构建渲染组件
   */

  private cacheRouters = new Map<string, DetachedRouteHandle>();

  // 是否允许复用路由
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return Boolean(route.data.keepalive);
  }

  // 存入路由(路由离开出发)
  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    const url = this.getFullRouteURL(route);
    this.cacheRouters.set(url, handle);
  }

  // 是否允许还原路由
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    const url = this.getFullRouteURL(route);
    return Boolean(route.data.keepalive) && this.cacheRouters.has(url);
  }

  // 获取存储路由
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    const url = this.getFullRouteURL(route);
    if (route.data.keepalive && this.cacheRouters.has(url)) {
      return this.cacheRouters.get(url);
    } else {
      return null;
    }
  }

  // 相同路由是否复用(路由进入触发)
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig && JSON.stringify(future.params) === JSON.stringify(curr.params);
  }
	//删除存储的路由
  deleteRouteCache(url: string): void {
    if (this.cacheRouters.has(url)) {
      const handle: any = this.cacheRouters.get(url);
      try {
        handle.componentRef.destory();
      } catch (e) { throw e }
      this.cacheRouters.delete(url);
    }
  }
	//删除存储的全部路由
  deleteAllRouteCache(): void {
    this.cacheRouters.forEach((handle: any, key: string) => {
      this.deleteRouteCache(key);
    });
  }

	//获取完整路由路径
  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) {
    return route.url.map(urlSegment => urlSegment.path);
  }
}

2.在app.nodule.ts文件中注册使用ReuseStrategy;

providers: [
	...
    { provide: RouteReuseStrategy, useClass: ReuseStrategy }
  ],

3.在需要使用路由复用的路由配置中做配置keepalive: true,就能实现路由复用的效果了。

const routes: Routes = [ ..., { path: 'test', component: TestComponent, data: { keepalive: true } } ];

直接在路由切换的时候就能控制那些路由需要使用路由复用就行。

实验结果为动态图,超过附件上传的最大限制,所以无法配图,有需要的可以参考uniontech官网源码。

总结

        angular RouteReuseStrategy 缓存(路由)组件很精简的实现了状态保留,数据保存的问题,可用于懒加载路由等各种不同的路由实现方式,简单好用,强烈推荐。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值