美文网首页angularangular2.X我爱编程
angular 路由复用策略实现懒路由下多tab页切换

angular 路由复用策略实现懒路由下多tab页切换

作者: 兜兜转转的小菊 | 来源:发表于2018-05-04 12:32 被阅读0次

    一、需求

    如图所示,打开多个页面,切换页面时能够保留之前打开的页面。且适应各种懒路由的切换,不单单是组件之间切换。


    需求.png

    二、废话不多说,直接上代码

    这是关键文件:app-reuse-strategy.ts
    这里我参考的漂_泊的方法,但是并不能实现同一个懒路由下不同路径下的路由切换, 例如:order/tab1和order/tab2同时存在的情况下,跳转会出现错误:Cannot reattach ActivatedRouteSnapshot created from a different route

    error.png
    然后找到了github上 dmitrimaltsev的解决方法,很好的实现了,感谢大神。
    然后就噔噔瞪~~:
    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 {
        const data = this.getRouteData(route);
        if (data) {
          return true;
        }
        return false;
      }
    
      /** 当路由离开时会触发。按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 {
        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;
        }
      }
    }
    

    这是重要步骤: 在AppModule中放入,一定放在这个文件下:

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

    到这里就把路由复用部分写好啦,接下来就是多tab页面的布局实现。
    这里参考的是博客园smiles的文章,以及漂_泊的文章。
    我根据需要修改了一些,在需要的路由下添加data数据,不需要复用的不添加:

    { path: '', component: VendorListComponent, data: {title: '商户列表', module: '/Vendor/List'}}
    

    home.component.ts中添加删除

    // 关闭选项标签
      closeUrl(module: string, isSelect: boolean, event: Event) {
        event.preventDefault();
        // 当前关闭的是第几个路由
        const index = this.menuList.findIndex(p => p.module === module);
        // 如果只有一个不可以关闭
        if (this.menuList.length === 1) return;
        this.menuList = this.menuList.filter(p => p.module !== module);
        // 删除复用
        AppReuseStrategy.deleteRouteSnapshot(module);
        if (!isSelect) return;
        // 显示上一个选中
        let menu = this.menuList[index - 1];
        if (!menu) {// 如果上一个没有下一个选中
          menu = this.menuList[index];
        }
        this.menuList.forEach(p => p.isSelect = p.module === menu.module);
        // 显示当前路由信息
        this.router.navigate(['/' + menu.module]);
      }
    

    三、参考

    1、Github Issues: dmitrimaltsev的解决方法
    2、博客园:smiles
    3、博客园:漂_泊
    4、Angular RouteReuseStrategy

    相关文章

      网友评论

        本文标题:angular 路由复用策略实现懒路由下多tab页切换

        本文链接:https://www.haomeiwen.com/subject/xrcdrftx.html