一、难点:
Angular 辅助路由 + 路由策略 会报错。Cannot reattach ActivatedRouteSnapshot created from a different route #13869,Github 上这条 issue 至今没有解决,做如题的功能难点就在于 Angular 的路由模块存在 bug,所以怎样解决或者规避这个 bug 是难点。
二、解决方案:
TAB 框架描述:
1. 左侧导航触发函数
(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
}
}]
}
];
策略部分
/** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.routeConfig ? route.routeConfig.data ? !!route.routeConfig.data.reuse : false : false;
}
/** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
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 在缓存中有的都认为允许还原路由 */
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];
}
/** 进入路由触发,判断是否同一路由 */
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig
}
网友评论