基于 Angular 2+ 的新版 Tab頁與路由策略

一、難點(diǎn):

Angular 輔助路由 + 路由策略 會(huì)報(bào)錯(cuò)夫啊。Cannot reattach ActivatedRouteSnapshot created from a different route #13869Github 上這條 issue 至今沒有解決,做如題的功能難點(diǎn)就在于 Angular 的路由模塊存在 bug谷扣,所以怎樣解決或者規(guī)避這個(gè) bug 是難點(diǎn)。

二、解決方案:

TAB 框架描述:

1. 左側(cè)導(dǎo)航觸發(fā)函數(shù)

(click)="updateTab(link.name, link.url, link.pcode, 'mname', link.asideUrl || 'sidemenus/foo')"

2. 中間訂閱邏輯

頁面部分:
<mat-tab-group [(selectedIndex)]="tabIndex" (selectedTabChange)="onSelectedTabChange($event)" style="height: 48px">
  <mat-tab *ngFor="let tabInfo of tabInfos; let i=index">
    <ng-template mat-tab-label>
      <span>{{tabInfo.name}}
        <i class="icon-close icons font-sm mt-4" style="margin: 2px 0 0 5px" (click)="closeTab(tabInfo.pcode, i)"></i>
      </span>
    </ng-template>
  </mat-tab>
</mat-tab-group>
TS 部分:
ngOnInit() {
  this.tabService.getCurrentTab().subscribe(tabInfo => {
    if (this.pCodeSet.has(tabInfo.pcode)) {
      for (let index = 0, len = this.tabInfos.length; index < len; index++) {
        if (this.tabInfos[index].pcode === tabInfo.pcode) {
          this.tabIndex = index;
          break;
        }
      }
    } else {
      this.pCodeSet.add(tabInfo.pcode);
      this.tabInfos.push(tabInfo);
      this.tabIndex = this.tabInfos.length - 1;
    }
  });
  this.router.navigate([{
    outlets: {
      primary: ['pages', 'blank'],
      aux: ['sidemenus', 'foo']
    }
  }], {
      skipLocationChange: true, relativeTo: this.route, replaceUrl: false
    }).then();
}

public onSelectedTabChange($event: MatTabChangeEvent | number) {
  this.tabIndex = $event instanceof MatTabChangeEvent ? $event.index : $event;
  if (this.tabIndex >= 0) {
    this.router.navigate([{
      outlets: {
        primary: this.tabInfos[this.tabIndex].url.split('/'),
        aux: (this.tabInfos[this.tabIndex].asideUrl || 'sidemenus/foo').split('/')
      }
    }], {
        skipLocationChange: true,
        relativeTo: this.route,
        replaceUrl: false,
        queryParams: { p: this.closePath }
      }).then(() => {
        this.closePath = '';
      });
  }
}

public closeTab(pcode: string, i: number) {
  this.pCodeSet.delete(pcode);
  if (i === this.tabInfos.length - 1) {
    this.showPreviousTab(i);
  } else {
    this.showNextTab(i);
  }
}

private showPreviousTab(closeIndex: number) {
  if (closeIndex - 1 < 0) {
    this.tabInfos = [];
    this._navigateToRoot();
  } else {
    this.tabInfos.splice(closeIndex, 1);
    if (this.tabIndex === closeIndex) {
      this.tabIndex--;
    }
  }
}

private showNextTab(closeIndex: number) {
  if (closeIndex + 1 >= this.tabInfos.length) {
    this.tabInfos = [];
    this._navigateToRoot();
  } else {
    this.tabInfos.splice(closeIndex, 1);
    if (closeIndex < this.tabIndex) {
      this.tabIndex--;
    } else if (closeIndex === this.tabIndex) {
      this.onSelectedTabChange(closeIndex)
    }
  }
}

private _navigateToRoot() {
  this.router.navigate([{
    outlets: {
      primary: ['pages', 'blank'],
      aux: ['sidemenus', 'foo']
    }
  }], {
      skipLocationChange: true, relativeTo: this.route,
      replaceUrl: false, queryParams: { p: '/' }
    }).then(() => {
      this.closePath = '';
    });
}

3.路由策略

路由定義部分
const routes: Routes = [
  {
    path: '',
    data: {
      title: 'Randy\'s Module'
    },
    children: [
      {
        path: 'bar',
        component: BarComponent,
        canActivate: [CanAuthProvide],
        data: {
          title: 'Randy Bar',
          reuse: true
        }
      },
      {
        path: 'user',
        component: UserManagementComponent,
        canActivate: [CanAuthProvide],
        data: {
          title: 'Randy User',
          reuse: true
        }
      }]
  }
];
策略部分
/** 表示對(duì)所有路由允許復(fù)用 如果你有路由不想利用可以在這加一些業(yè)務(wù)邏輯判斷 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
  return route.routeConfig ? route.routeConfig.data ? !!route.routeConfig.data.reuse : false : false;
}

/** 當(dāng)路由離開時(shí)會(huì)觸發(fā)会涎。按path作為key存儲(chǔ)路由快照&組件當(dāng)前實(shí)例對(duì)象 */
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
  if(handle !== null) {
    SimpleReuseStrategy.handlers[route.routeConfig.path] = handle;
  }
  switch (route.queryParams.p) {
    case '':
      break;
    case '/':
      break;
    default:
      console.log(SimpleReuseStrategy.handlers);
      delete SimpleReuseStrategy.handlers[route.queryParams.p];
  }
}

/** 若 path 在緩存中有的都認(rèn)為允許還原路由 */
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
  return !!route.routeConfig && !!SimpleReuseStrategy.handlers[route.routeConfig.path];
}

/** 從緩存中獲取快照裹匙,若無則返回null */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
  if (!route.routeConfig) {
    return null;
  }
  if (route.routeConfig.loadChildren) {
    return null;
  }
  return SimpleReuseStrategy.handlers[route.routeConfig.path];
}

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

參考文獻(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末末秃,一起剝皮案震驚了整個(gè)濱河市概页,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌练慕,老刑警劉巖惰匙,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铃将,居然都是意外死亡项鬼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門劲阎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绘盟,“玉大人,你說我怎么就攤上這事悯仙×湔保” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵锡垄,是天一觀的道長(zhǎng)沦零。 經(jīng)常有香客問我,道長(zhǎng)偎捎,這世上最難降的妖魔是什么蠢终? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮茴她,結(jié)果婚禮上寻拂,老公的妹妹穿的比我還像新娘。我一直安慰自己丈牢,他們只是感情好祭钉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著己沛,像睡著了一般慌核。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上申尼,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天垮卓,我揣著相機(jī)與錄音,去河邊找鬼师幕。 笑死粟按,一個(gè)胖子當(dāng)著我的面吹牛诬滩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灭将,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼疼鸟,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了庙曙?” 一聲冷哼從身側(cè)響起空镜,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捌朴,沒想到半個(gè)月后吴攒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡男旗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年舶斧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片察皇。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泽台,靈堂內(nèi)的尸體忽然破棺而出什荣,到底是詐尸還是另有隱情,我是刑警寧澤怀酷,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布稻爬,位于F島的核電站,受9級(jí)特大地震影響蜕依,放射性物質(zhì)發(fā)生泄漏桅锄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一样眠、第九天 我趴在偏房一處隱蔽的房頂上張望友瘤。 院中可真熱鬧,春花似錦檐束、人聲如沸辫秧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盟戏。三九已至,卻和暖如春甥桂,著一層夾襖步出監(jiān)牢的瞬間柿究,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工黄选, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝇摸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像探入,于是被迫代替她去往敵國(guó)和親狡孔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容