Angular6路由复用策略解读

本文除了介绍路由复用策略外,还实现了父子路由如何复用的问题,项目见末尾;

1、父路由和子路由页面的tab不应该同时存在,否则,切换时容易报以下错误:

Cannot reattach ActivatedRouteSnapshot with a different number of children

2、子路由实例化时可以根据路由缓存同时恢复其对应的父路由;具体详见项目中的路由复用策略;

 

路由导航过程:创建新的路由节点;激活路由节点(停用旧路由、激活新路由);

路由复用策略各方法执行流程如下:

 

其中,可以看到一个路由复用过程中,可能会出现俩次retrieve操作。这是因为第一次调用是为了获取缓存路由对应的快照对象TreeNode,第二次调用是为了获取缓存对应的组件实例化对象ComponentRef

路由复用详细解析:

创建新的路由节点:

初始化节点时,通过shouldReuseRoute判断未来路由是否与当前路由相同,若相同,则赋当前路由页面快照到新创建节点的初始值;否则,判断是否存在已有缓存,若有,则通过retrieve同样赋快照初始值,否则,则默认初始化节点;

function createNode(
    routeReuseStrategy: RouteReuseStrategy, curr: TreeNode<ActivatedRouteSnapshot>,
    prevState?: TreeNode<ActivatedRoute>): TreeNode<ActivatedRoute> {
  // reuse an activated route that is currently displayed on the screen
  if (prevState && routeReuseStrategy.shouldReuseRoute(curr.value, prevState.value.snapshot)) {
    const value = prevState.value;
    value._futureSnapshot = curr.value;
    const children = createOrReuseChildren(routeReuseStrategy, curr, prevState);
    return new TreeNode<ActivatedRoute>(value, children);

    // retrieve an activated route that is used to be displayed, but is not currently displayed
  } else {
    const detachedRouteHandle =
        <DetachedRouteHandleInternal>routeReuseStrategy.retrieve(curr.value);
    if (detachedRouteHandle) {
      const tree: TreeNode<ActivatedRoute> = detachedRouteHandle.route;
      setFutureSnapshotsOfActivatedRoutes(curr, tree);
      return tree;

    } else {
      const value = createActivatedRoute(curr.value);
      const children = curr.children.map(c => createNode(routeReuseStrategy, c));
      return new TreeNode<ActivatedRoute>(value, children);
    }
  }
}

 

停用旧路由:

停用路由及其子路由:判断该路由是否要保存shouldDetach,若要,则保存store该路由;

private deactivateRouteAndItsChildren(
      route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void {
    if (this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
      this.detachAndStoreRouteSubtree(route, parentContexts);
    } else {
      this.deactivateRouteAndOutlet(route, parentContexts);
    }
  }

private detachAndStoreRouteSubtree(
      route: TreeNode<ActivatedRoute>, parentContexts: ChildrenOutletContexts): void {
    const context = parentContexts.getContext(route.value.outlet);
    if (context && context.outlet) {
      const componentRef = context.outlet.detach();
      const contexts = context.children.onOutletDeactivated();
      this.routeReuseStrategy.store(route.value.snapshot, {componentRef, route, contexts});
    }
  }

 

激活新路由:

激活未来路由时,判断是否可以取缓存路由(shouldAttach),若可以,则retrieve获取缓存路由,且通过store置空缓存对象;

if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
          const stored =
              (<DetachedRouteHandleInternal>this.routeReuseStrategy.retrieve(future.snapshot));
          this.routeReuseStrategy.store(future.snapshot, null);
          context.children.onOutletReAttached(stored.contexts);
          context.attachRef = stored.componentRef;
          context.route = stored.route.value;
          if (context.outlet) {
            // Attach right away when the outlet has already been instantiated
            // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
            context.outlet.attach(stored.componentRef, stored.route.value);
          }
          advanceActivatedRouteNodeAndItsChildren(stored.route);
        }

 

具体路由复用策略的实现,可参考本人git上发布的实例项目:

https://github.com/007katoo/Ng6-Manage

 

参考文章:

1、兜兜转转的小菊——angular 路由复用策略实现懒路由下多tab页切换

2、NG-ZORRO

3、及文章1里的所有引用文章;

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值