我爱编程

基于 Angular 2+ 的新版 Tab页与路由策略

2018-04-20  本文已影响0人  环零弦

一、难点:

Angular 辅助路由 + 路由策略 会报错。Cannot reattach ActivatedRouteSnapshot created from a different route #13869Github 上这条 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
}

参考文献

上一篇下一篇

猜你喜欢

热点阅读