一、難點(diǎn):
Angular 輔助路由 + 路由策略 會(huì)報(bào)錯(cuò)夫啊。Cannot reattach ActivatedRouteSnapshot created from a different route #13869,Github 上這條 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
}