angular4 路由重用策略 RouterReuseStrategy

单页面应用现在是主流,随之而来的缺点:页面间切换时不能保存状态

angular4出了一个RouteReuseStrategy路由重用策略可以让组件所有的state和渲染好的html存起来,然后在切回去的时候再调出来。

export declare abstract class RouteReuseStrategy{
   abstract shouldReuseRoute():Boolean
   abstract shouldAttach():Boolean
   abstract retrieve():DetachedRouteHandle | null
   abstract shouldDetach():Boolean
   abstract store():void
}

替换一旦发生,某些组件将被丢弃

这时shouldDetech,store将被调用,用于缓存即将被丢弃的组件

有组件丢弃,自然有组件替补进来

这时shouldAttach retreive将被调用,用于调出缓存的组件

🌊 应用场景

1.进入某个路由页面,进行操作,切换页面再返回,能还原到之前的操作状态;

2.切换右边的tab,能进入到对应的路由页面(操作后的状态);

3.点击右边tab里的关闭按钮或页面上的关闭按钮,删除某个路由页面的快照,再次点开这个路由页面,页面恢复初始状态;

 

🌊 下面是具体实现

要注意的点:

1. store方法:存储上一个页面的快照

2.关闭路由有几种情况:

    i 打开A页面后 打开B页面 关闭B页面(此时B页面没有快照) -> 触发store方法

    ii 打开A页面后 打开B页面 关闭A页面 (此时A页面有快照)   -> 不触发store方法

  iii 打开A页面后 打开B页面 回到A页面 关闭A页面 (此时A页面有快照) ->不触发store方法

    iii 打开A页面后 打开B页面 回到A页面 关闭B页面 (此时B页面有快照) ->不触发store方法

   因此页面在没有快照的时候关闭  需要在store方法里做一个暂缓删除的操作(先记录key 进去新页面后 再删除key)

   这样页面的ngOnDestroy()方法才能执行  才能避免事件重复监听(在ngOnDestroy()中执行)

相关的知识点:

ActivatedRouteSnapshot:包含当前插座中加载组件某一特定时间路由信息

RouteReuseStrategy:路由复用策略

DetachedRouteHandle:组件当前所有状态(路由快照

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

export class ExtensionRouteReuseStrategy implements RouteReuseStrategy {
  private static waitDelete:string;
  public static storedRoutes: Map<string, DetachedRouteHandle> = new Map<string, DetachedRouteHandle>();

  constructor(){
    //关闭操作(右上角或者history页面)
    this.storageNotifyRouter.destoryTopic.subscribe((key) => {
      this.processDestory(key);
    });
 };


 //是否缓存【离开路由时触发】
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    if (route.data && route.data.key) {
      return true;
    }
    return false;
  }

  //缓存组件【离开路由时触发】
  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    const key = this.findStoreKey(route);
    const key$$ = this.lastClosedKey + _SPLIT;
    //未存储快照的情况下 跳转新页面 再删key
    if (this.waitDeleteRoutes.size > 0) {
      const array = Array.from(this.waitDeleteRoutes.keys());
      for (const deletekey of array) {
        if (deletekey == key) {
          const oldHandle = handle as { componentRef: ComponentRef<any> };
          oldHandle.componentRef.destroy();
        }
        this.waitDeleteRoutes.delete(deletekey);
      }
      return;
    }
    //存储上一个页面快照 进入新页面
    if (handle && !(key === this.lastClosedKey || key.startsWith(key$$))) {
      this.lastClosedKey = '';
      this.storedRoutes.set(key, handle);
    }
  }

 //是否还原【进入路由时触发】
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    const key = this.findRetrieveKey(route);
    const result: boolean = !!key && !!this.storedRoutes.get(key);
    return result;
  }

  //还原路由【进入路由时触发】
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    const key = this.findRetrieveKey(route);
    let handle = null;
    if (key && this.storedRoutes.get(key)) {
      handle = this.storedRoutes.get(key);
      this.routerNotifyStorage.notifyRetrieve(key);
    }
    return handle;
  }

 //是否复用路由【进入路由时触发】
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    const result: boolean = future.routeConfig === curr.routeConfig;
    return result;
  }

  findStoreKey(route: ActivatedRouteSnapshot): string {
    let key = "";
    if (route.data && route.data.key) {
      if (route.children[0] && route.children[0].data && route.children[0].data.key) {
        this.findStoreKey(route.children[0]);
      } else {
        key = route.data.key;
      }
    }
    return key;
  }

  findRetrieveKey(route: ActivatedRouteSnapshot): string {
    let key = "";
    if (route.data && route.data.key) {
      key = route.data.key;
    }
    return key;
  }

  processDestory(key: string, waiteDelete: boolean = true) {
    this.lastClosedKey = key;
    let existKey: boolean = false;
    const array: string[] = Array.from(this.storedRoutes.keys());
    for (const keyStored of array) {
      const key$$ = key + _SPLIT;
      //存储快照的情况下 删除快照
      if (key === keyStored || keyStored.startsWith(key$$)) {
        const oldHandle = this.storedRoutes.get(keyStored) as { componentRef: ComponentRef<any> };
        oldHandle.componentRef.destroy();
        this.storedRoutes.delete(keyStored);
        existKey = true;
      }
    }
    //未存储快照 先存当前页面key
    if (!existKey && waiteDelete) {
      this.waitDeleteRoutes.add(key);
    }
  }
 
}

 

  

 

🌊 后续

保存快照

在离开路由时保存上一个页面快照,并emit一个事件给左边的菜单组件和右边的tab组件,告诉它们路由路径已改变,同时把新的路由路径作为参数传过去

然后在左边的菜单组件和右边的tab组件里subscribe事件里去监听变化,替换新的路由路径。

这样在点击它们的时候就会重定向到新的路由路径,而快照已保存。

 

删除快照

点击右边tab组件里的关闭按钮或者点击页面上的关闭按钮时,emit一个删除快照的事件,同时把路由路径作为参数传过去

然后在路由复用策略的ts文件中的subscribe事件里去监听这个事件,然后执行对应路由的processDestroy()方法

  

 

posted @ 2018-05-11 18:13  Artimis  阅读(3850)  评论(0编辑  收藏  举报