angular 路由復(fù)用策略實現(xiàn)懶路由下多tab頁切換

一、需求

如圖所示,打開多個頁面,切換頁面時能夠保留之前打開的頁面。且適應(yīng)各種懶路由的切換,不單單是組件之間切換。


需求.png

二、廢話不多說,直接上代碼

這是關(guān)鍵文件:app-reuse-strategy.ts
這里我參考的漂_泊的方法,但是并不能實現(xiàn)同一個懶路由下不同路徑下的路由切換, 例如:order/tab1和order/tab2同時存在的情況下,跳轉(zhuǎn)會出現(xiàn)錯誤:Cannot reattach ActivatedRouteSnapshot created from a different route

error.png

然后找到了github上 dmitrimaltsev的解決方法,很好的實現(xiàn)了,感謝大神。
然后就噔噔瞪~~:

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;  // 當前頁存儲過時需要刪除

  /** 進入路由觸發(fā),判斷是否是同一路由 */
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
  }

  /** 表示對所有路由允許復(fù)用 如果你有路由不想利用可以在這加一些業(yè)務(wù)邏輯判斷,這里判斷是否有data數(shù)據(jù)判斷是否復(fù)用 */
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    const data = this.getRouteData(route);
    if (data) {
      return true;
    }
    return false;
  }

  /** 當路由離開時會觸發(fā)。按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 }
  ]

到這里就把路由復(fù)用部分寫好啦,接下來就是多tab頁面的布局實現(xiàn)。
這里參考的是博客園smiles的文章,以及漂_泊的文章。
我根據(jù)需要修改了一些,在需要的路由下添加data數(shù)據(jù),不需要復(fù)用的不添加:

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

home.component.ts中添加刪除

// 關(guān)閉選項標簽
  closeUrl(module: string, isSelect: boolean, event: Event) {
    event.preventDefault();
    // 當前關(guān)閉的是第幾個路由
    const index = this.menuList.findIndex(p => p.module === module);
    // 如果只有一個不可以關(guān)閉
    if (this.menuList.length === 1) return;
    this.menuList = this.menuList.filter(p => p.module !== module);
    // 刪除復(fù)用
    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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,034評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 一、SPA的概念 首先明確一個概念,SPA,全稱為Single Page Application單頁應(yīng)用,一個單頁...
    耦耦閱讀 6,071評論 0 3
  • 又去了校園 突然覺得校園離自己好遠了,明明還未真正離開卻已經(jīng)開始想念那種無憂的生活。 4年大學(xué)成長了很多 如今進去...
    星傑閱讀 99評論 0 0
  • 只要是女人,都喜歡過夏天。豐滿的露胸,骨感的露腿,窈窕的露腰,風光無限。不知道別的女人,我反正也討厭夏天。每到七、...
    子聿閱讀 13,592評論 104 583

友情鏈接更多精彩內(nèi)容