Javascript 选项卡应用程序-角度6

Javascript 选项卡应用程序-角度6,javascript,angular,angular-material,single-page-application,Javascript,Angular,Angular Material,Single Page Application,我在构建角度应用程序时面临一个问题。我需要一个选项卡应用程序,而不是路由,也就是说:每当用户单击应用程序中的新链接,而不是将应用程序路由到该组件时,它将: 检查选项卡是否已打开,然后选择它 如果未打开,则在导航选项卡的选项卡列表中添加一个新选项卡,并将其选中 每当用户单击该选项卡时,路由器将更改为新选项卡 在浏览器中回击时,系统将选择上一个选项卡,或打开最后一个关闭的选项卡 我的初步计划是: 从应用程序中移除插座并添加[matTabNavBar] 聆听管线中的任何更改,并获取与管线相关的组件和参

我在构建角度应用程序时面临一个问题。我需要一个选项卡应用程序,而不是路由,也就是说:每当用户单击应用程序中的新链接,而不是将应用程序路由到该组件时,它将:

  • 检查选项卡是否已打开,然后选择它
  • 如果未打开,则在导航选项卡的选项卡列表中添加一个新选项卡,并将其选中
  • 每当用户单击该选项卡时,路由器将更改为新选项卡
  • 在浏览器中回击时,系统将选择上一个选项卡,或打开最后一个关闭的选项卡
  • 我的初步计划是:

  • 从应用程序中移除插座并添加[matTabNavBar]
  • 聆听管线中的任何更改,并获取与管线相关的组件和参数
  • 将路由用作选项卡的键(以检查选项卡是否已存在)
  • 如果组件不存在,则动态创建一个新选项卡并将组件添加到其中,然后选择该选项卡
  • 你能帮我吗?我需要所有步骤(收集想法)的指导方针或最佳实践。如果有一些组件或包可以帮助我实现这一点。谢谢

    编辑:要清除示例,


    假设我有一个从数据库加载的系统中的项目列表,当我想要编辑一个项目时,我将能够在它自己的选项卡中打开它。所以我可以同时打开多个项目。当我通过“新建”选项卡添加新项时,我也应该能够在其自己的选项卡中打开该记录。它们不仅仅是我想要在它们之间路由的静态选项卡列表

    不清楚为什么您认为必须放弃路由才能使用选项卡导航。选项卡导航和路由不是不兼容的。要将MatTabNavBar和MatTabLink用于路由,请设置应用程序路由,使每个“选项卡”都是路由,将路由器选项添加到mat选项卡链接元素,并使用路由器出口承载选项卡内容。这应该比您计划的要容易得多,因为您不需要担心动态选项卡内容的“创建”和后退按钮的使用

    下面是从基本示例中选择的代码,完整演示如下:

    模板

    <nav mat-tab-nav-bar [backgroundColor]="background">
        <a mat-tab-link routerLink="test-one" routerLinkActive #rla1="routerLinkActive" [active]="rla1.isActive">Test One</a>
        <a mat-tab-link routerLink="test-two" routerLinkActive #rla2="routerLinkActive" [active]="rla2.isActive">Test Two</a>
    </nav>
    <router-outlet></router-outlet>
    

    我能够通过以下方式实现我想要的:

  • 从应用程序中删除路由插座
  • 添加一个Mat选项卡组,而不是它
  • 收听应用程序中的路由事件
  • 从布线中获取所需的组件名称和参数
  • 将其存储在密钥列表中,以便能够跟踪打开的内容并防止多次打开同一组件(取决于需要)
  • 使用*ngComponentOutlet在UI中动态加载组件
  • 使用可注入类传递参数
  • 使用带有observable的单例注入服务管理选项卡之间的事件
  • 而不是出口

    <mat-tab-group [selectedIndex]="selectedTab" backgroundColor="primary" color="primary" (selectedTabChange)="selectedTabChanged($event)" style="height:100%;">
          <mat-tab label="Dashboard">
            Dashboard Component -- none closable tab, does not depend on routing.
          </mat-tab>
          <mat-tab *ngFor="let tab of tabsComponents; index as i">
            <ng-template mat-tab-label>
              {{tab.title | translate}}
              <button mat-icon-button class="close-icon"
                      (click)="closeTab($event,i)">
                <mat-icon class="close-icon ">
                  close
                </mat-icon>
              </button>
            </ng-template>
            <ng-container *ngComponentOutlet="tab.component; injector:tab.params" ></ng-container>
          </mat-tab>
        </mat-tab-group>
    
    变量:

    tabsKeys: string[] = [];//store the keys of the opened tabs
    tabsComponents: ITechTab[] = [];// stores information about the component in each tab
    selectedTab = 0; // store the index of the selected tab
    
    按索引关闭选项卡功能:

    closeTabByIndex(i: number) {
    this.tabsKeys.splice(i, 1);
    let removedtabs = this.tabsComponents.splice(i, 1);
    if (this.router.url == removedtabs[0].path) {
      if (i == 0 && this.tabsComponents.length == 0) {
        this.router.navigate(['/dashboard']);
      } else {
        this.router.navigate([this.tabsComponents[i - 1].path]);
      }
    }
    }
    

    感谢您的回复,删除插座是因为我怀疑当我移动到另一个选项卡时,我会丢失在单个选项卡中所做的更改。我将尝试你的解决方案,如果它有效,我将标记它。感谢这是一个静态选项卡列表,请参见问题末尾的编辑,如果我有一个动态项目列表,并且我希望能够在选项卡之间移动时同时打开多个项目而不丢失编辑的数据,该怎么办?听起来好像你想要的与路由无关,所以使用短语“而不是路由”造成混乱。考虑编辑您的问题描述,以排除对路由的任何引用,并仅解释您试图实现的目标。这可能有助于其他人更好地理解。嗨,你解决问题了吗?嗨,是的,我解决了。我将发布它,谢谢,这是否支持延迟加载?因为您删除了
    路由器插座
    !我不是100%确定,但我在模块的延迟加载中使用了它,它工作得很好。
    this.routerEventSub = router.events.pipe(filter(event => event instanceof NavigationEnd))
      .subscribe((routeChange: NavigationEnd) => {
        this.layout.adjustLayout({ route: routeChange.url });
    
        let child = route.snapshot.firstChild.firstChild;
        console.log(child);
        if (this.tabsKeys.indexOf(routeChange.url) == -1) {
          this.tabsKeys.push(routeChange.url);
    
          let myParams: iTechParam = {
            _params: child.params,
            _queryParam: child.queryParams,
            _path:router.url
          }
          let params = Injector.create([
            { provide: iTechParam, useValue: myParams }
          ], this.inj);
          this.tabsComponents.push({ title: child.data['title'], component: child.component, params: params, path: router.url });
          this.selectedTab = this.tabsKeys.length;
        } else {
          this.selectedTab = this.tabsKeys.indexOf(routeChange.url) + 1;//+1 is because the dashboard tab, none-closable one
        }
    
    
      });
    
    tabsKeys: string[] = [];//store the keys of the opened tabs
    tabsComponents: ITechTab[] = [];// stores information about the component in each tab
    selectedTab = 0; // store the index of the selected tab
    
    closeTabByIndex(i: number) {
    this.tabsKeys.splice(i, 1);
    let removedtabs = this.tabsComponents.splice(i, 1);
    if (this.router.url == removedtabs[0].path) {
      if (i == 0 && this.tabsComponents.length == 0) {
        this.router.navigate(['/dashboard']);
      } else {
        this.router.navigate([this.tabsComponents[i - 1].path]);
      }
    }
    }