好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

用于实现tab页签切换页面的angular路由复用策略

使用场景

 打开菜单页面的时候,出现对应页面的页签。切换页签,原来的页面信息状态保留,关闭页签则保留的信息删除。使用路由复用策略,保存路由快照。
实现效果如图所示
实现过程

  概述:

1、在app.module.ts注册

   providers: [
    {  provide: RouteReuseStrategy,  useClass: CustomReuseStrategy }
  ],
    

2、新建RouteReuseStrategy

 新建一个 CustomReuseStrategy .ts   

贴上代码(解决了位于三级菜单的页面与位于一级菜单或者二级菜单无法跳转的问题之后的代码)

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

 interface IRouteConfigData {
  reuse:  boolean;
}

 interface ICachedRoute {
  handle: DetachedRouteHandle;
  data: IRouteConfigData;
}

 @Injectable()
 export  class AppReuseStrategy  implements RouteReuseStrategy {
   private  static routeCache =  new Map< string, ICachedRoute>();
   private  static waitDelete:  string;  //  当前页未进行存储时需要删除
   private  static currentDelete:  string;   //  当前页存储过时需要删除

   /**  进入路由触发,判断是否是同一路由 */
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot):  boolean {
     return future.routeConfig === curr.routeConfig;
  }

   /**  表示对所有路由允许复用  如果你有路由不想利用可以在这加一些业务逻辑判断,这里判断是否有data 数据判断是否复用 */
  shouldDetach(route: ActivatedRouteSnapshot):  boolean {
     if (!route.data.keep) {
       return  false;
    }
     if (!route.routeConfig || route.routeConfig.loadChildren) {
       return  false;
    }
     return  true;
  }

   /**  当路由离开时会触发。按path 作为key 存储路由快照& 组件当前实例对象 */
  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle):  void {
     const url =  this.getFullRouteUrl(route);
     const data =  this.getRouteData(route);
     if (AppReuseStrategy.waitDelete && AppReuseStrategy.waitDelete === url) {
       //  如果待删除是当前路由,且未存储过则不存储快照
      AppReuseStrategy.waitDelete =  null;
       return  null;
    }  else {
       //  如果待删除是当前路由,且存储过则不存储快照
       if (AppReuseStrategy.currentDelete && AppReuseStrategy.currentDelete === url) {
        AppReuseStrategy.currentDelete =  null;
         return  null;
      }  else {
        AppReuseStrategy.routeCache.set(url, {handle, data});
         this.addRedirectsRecursively(route);
      }
    }
  }


   /**  若 path  在缓存中有的都认为允许还原路由 */
  shouldAttach(route: ActivatedRouteSnapshot):  boolean {
     const url =  this.getFullRouteUrl(route);
     return AppReuseStrategy.routeCache.has(url);
  }

   /**  从缓存中获取快照,若无则返回nul */
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
     const url =  this.getFullRouteUrl(route);
     const data =  this.getRouteData(route);
     return data && AppReuseStrategy.routeCache.has(url)
      ? AppReuseStrategy.routeCache.get(url).handle
      :  null;
  }

   private addRedirectsRecursively(route: ActivatedRouteSnapshot):  void {
     const config = route.routeConfig;
     if (config) {
       if (!config.loadChildren) {
         const routeFirstChild = route.firstChild;
         const routeFirstChildUrl = routeFirstChild ?  this.getRouteUrlPaths(routeFirstChild).join( '/') :  '';
         const childConfigs = config.children;
         if (childConfigs) {
           const childConfigWithRedirect = childConfigs.find(  c => c.path ===  '' && !!c.redirectTo);
           if (childConfigWithRedirect) {
            childConfigWithRedirect.redirectTo = routeFirstChildUrl;
          }
        }
      }
      route.children.forEach(  childRoute =>  this.addRedirectsRecursively(childRoute));
    }
  }

   private getFullRouteUrl(route: ActivatedRouteSnapshot):  string {
     return  this.getFullRouteUrlPaths(route).filter( Boolean).join( '/').replace( '/',  '_');
  }

   private getFullRouteUrlPaths(route: ActivatedRouteSnapshot):  string[] {
     const paths =  this.getRouteUrlPaths(route);
     return route.parent ? [...this.getFullRouteUrlPaths(route.parent), ...paths] : paths;
  }

   private getRouteUrlPaths(route: ActivatedRouteSnapshot):  string[] {
     return route.url.map(  urlSegment => urlSegment.path);
  }

   private getRouteData(route: ActivatedRouteSnapshot): IRouteConfigData {
     return route.routeConfig && route.routeConfig.data  as IRouteConfigData;
  }

   /**  用于删除路由快照*/
   public  static deleteRouteSnapshot(url:  string):  void {
     let arr:  any = []
    arr = url.split( '?')
    url = arr[ 0]
     if (url[ 0] ===  '/') {
      url = url.substring( 1);
    }
    url = url.replace( '/',  '_');
     if (AppReuseStrategy.routeCache.has(url)) {
      AppReuseStrategy.routeCache.delete(url);
      AppReuseStrategy.currentDelete = url;
    }  else {
      AppReuseStrategy.waitDelete = url;
    }
  }
}
                                                                                                                                                
 附上相关API文档:
   [ RouteReuseStrategy]( https://www.angular.cn/api/router/RouteReuseStrategy)   

3、关闭页签的时候,同时删除快照

 解决办法:在实现页签的页面,关闭按钮那里,删除页签数组之后,加入以下代码: 
      // link 就是当前关闭页面的路由
    setTimeout(  ()=>{
      AppReuseStrategy.deleteRouteSnapshot(link);
    },  0)
      

4、其他

 值得注意的是,如果页面中有定时器,离开页面的时候,需要暂时删除该定时器。
但保存路由快照之后,离开该页面的时候,不经过ngOnDestroy。
解决办法: 
  this.router.events.filter(  event => event  instanceof NavigationEnd)
      .subscribe( ( event) => {
         //  路由data 的标题
        clearInterval( this.interval)
      });           

查看更多关于用于实现tab页签切换页面的angular路由复用策略的详细内容...

  阅读:32次