Javascript 标题单击时角度2动态加载选项卡

Javascript 标题单击时角度2动态加载选项卡,javascript,angular,tabs,angular2-directives,Javascript,Angular,Tabs,Angular2 Directives,我已经开发了一个自定义选项卡组件,使用Angular 2,工作正常。 这就是它的用法 <us-tab-verticle> <vtab-content [tabTitle]="'Basic Information'"><basic-info> </basic-info></vtab-content> <vtab-content [tabTitle]="'VAT Settings'"><vat-settin

我已经开发了一个自定义选项卡组件,使用Angular 2,工作正常。 这就是它的用法

<us-tab-verticle>
    <vtab-content [tabTitle]="'Basic Information'"><basic-info> </basic-info></vtab-content>
    <vtab-content [tabTitle]="'VAT Settings'"><vat-settings> </vat-settings></vtab-content>
    <vtab-content [tabTitle]= "'Economy Settings'"><economy-settings> </economy-settings></vtab-content>
    <vtab-content [tabTitle]="'Access Profiles'"><access-profiles> </access-profiles></vtab-content>
</us-tab-verticle>
我需要在单击每个选项卡的标题时加载每个组件。
我知道你能适应这种情况。但是我不知道如何实现。

我尝试使用
ngComponentOutlet
指令来重现您的结构。以下是选项卡容器:

@Component({
  selector: 'tab',
  template: ''
})
export class TabComponent {
  @Input() title: string;
  @Input() contentRef: any;
  active = false;
}
这是一个非常简单的组件,它知道自己的选项卡名称、活动状态和主体组件引用,当有人选择选项卡时,应该加载这些引用

然后,我们创建几个将动态加载的车身组件:

@Component({
  selector: 'tab-content',
  template: `<p>Hey</p>`
})
export class TabContentComponent {}

@Component({
  selector: 'tab-content-alternative',
  template: `<p>Hey, this is an alternative content</p>`
})
export class TabContentAlternativeComponent {}
@组件({
选择器:“选项卡内容”,
模板:`嘿

` }) 导出类TabContentComponent{} @组成部分({ 选择器:“选项卡内容替代项”, 模板:`嘿,这是一个替代内容

` }) 导出类TabContentAlternativeComponent{}
以下是具有选项卡渲染的选项卡容器组件和用于动态实体组件的空占位符:

@Component({
  selector: 'tab-container',
  template: `
    <div class="tab-header">
      <div class="tab" *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active">{{tab.title}}</div>
    </div>

    <div class="tab-content">
      <ng-container *ngComponentOutlet="content | async"></ng-container>
    </div>
  `,
})
export class TabContainerComponent implements AfterContentInit {
  @ContentChildren(TabComponent) tabs: QueryList<TabComponent>;

  private contentSbj = new BehaviorSubject<BasicContent>(null);
  content = this.contentSbj.asObservable();

  ngAfterContentInit() {
    const activeTabs = this.tabs.filter((tab) => tab.active);
    if (activeTabs.length === 0) {
      this.selectTab(this.tabs.first);
    }
  }

  selectTab(tab: TabComponent) {
    this.tabs.toArray().forEach(tab => tab.active = false);
    tab.active = true;
    this.contentSbj.next(tab.contentRef);
  }
}
@组件({
选择器:“选项卡容器”,
模板:`
{{tab.title}}
`,
})
导出类TabContainerComponent在ContentInit之后实现{
@ContentChildren(TabComponent)选项卡:QueryList;
private contentSbj=新行为主体(null);
content=this.contentSbj.asObservable();
ngAfterContentInit(){
const activeTabs=this.tabs.filter((tab)=>tab.active);
如果(activeTabs.length==0){
this.selectTab(this.tabs.first);
}
}
选择选项卡(选项卡:选项卡组件){
this.tabs.toArray().forEach(tab=>tab.active=false);
tab.active=true;
this.contentSbj.next(tab.contentRef);
}
}
这就是如何在某些父组件中使用它:

import {TabContentComponent} from './tab/tab-content.component'
import {TabContentAlternativeComponent} from './tab/tab-content-alternative.component'
...

@Component({
  selector: 'my-app',
  template: `
    <tab-container>
      <tab title="Tab 1" [contentRef]="normalContent"></tab>
      <tab title="Tab 2" [contentRef]="alternativeContent"></tab>
    </tab-container>
  `,
})
export class App {
  normalContent = TabContentComponent;
  alternativeContent = TabContentAlternativeComponent;
}
从“./tab/tab content.component”导入{TabContentComponent}
从“./tab/tab content alternative.component”导入{TabContentAlternativeComponent}
...
@组成部分({
选择器:“我的应用程序”,
模板:`
`,
})
导出类应用程序{
normalContent=TabContentComponent;
alternativeContent=TabContentAlternativeComponent;
}

这里有很多解决方案,如果你想改进你的解决方案,我建议使用
*ngIf
。但请注意,每次
*ngIf
状态更改时,您都会销毁并创建一个新组件

我建议您使用
children
attribue查看
RouterModule

一个小例子:(不确定你能不能马上让它工作,但我在我的应用程序中使用了类似的东西)

//Router.ts
从“@angular/core”导入{NgModule};
从'@angular/router'导入{Routes,RouterModule};
常数路由:路由=[
{
路径:“”,
儿童:[
{路径:'tab1',组件:Tab1Component},
{路径:'tab2',组件:Tab2Component},
]
},
{路径:'**',重定向到:'}//是否修改默认选项卡?
];
@NGD模块({
导入:[RouterModule.forRoot(路由)],
导出:[路由模块]
})
导出类AppRoutingModule{}
导出常量路由组件=[Tab1Component,Tab2Component];
//AppModule.ts
进口:[批准模块]
声明:[
路由组件
],
//main.html
//选项卡组件的内容将显示在下面

在我看来,这种方式使您的应用程序更易于阅读(声明式路由),而不是使用外部服务和组件来管理选项卡的状态。

利用组件的
动态组件
延迟加载
。对于这个问题,我们有很多方法来解决,我建议您寻找已实现解决方案的。您可以使用*ngIf=“active”而不是[hidden],这样,只有当TrueFrom根据您的解决方案
标题内容映射是TabContainerComponent的依赖项时,它才会插入组件。所以这不能作为一个通用组件使用。我当前的实现可以在项目的任何地方使用,并且可以创建任意数量的选项卡。我的想法是在选项卡名称和它们的内容之间有一些映射。我可以去掉它,直接将内容组件作为输入参数传递到选项卡中。稍微更新了。请查看我的最终解决方案。现在,选项卡容器组件可以根据需要拥有任意多的选项卡(请参见app.ts),而无需任何外部依赖项,并且所有逻辑都隐藏在内部。也更新了答案。*ngIf不适用于我的实现。我将尝试使用路由器更改选项。
@Component({
  selector: 'tab',
  template: ''
})
export class TabComponent {
  @Input() title: string;
  @Input() contentRef: any;
  active = false;
}
@Component({
  selector: 'tab-content',
  template: `<p>Hey</p>`
})
export class TabContentComponent {}

@Component({
  selector: 'tab-content-alternative',
  template: `<p>Hey, this is an alternative content</p>`
})
export class TabContentAlternativeComponent {}
@Component({
  selector: 'tab-container',
  template: `
    <div class="tab-header">
      <div class="tab" *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active">{{tab.title}}</div>
    </div>

    <div class="tab-content">
      <ng-container *ngComponentOutlet="content | async"></ng-container>
    </div>
  `,
})
export class TabContainerComponent implements AfterContentInit {
  @ContentChildren(TabComponent) tabs: QueryList<TabComponent>;

  private contentSbj = new BehaviorSubject<BasicContent>(null);
  content = this.contentSbj.asObservable();

  ngAfterContentInit() {
    const activeTabs = this.tabs.filter((tab) => tab.active);
    if (activeTabs.length === 0) {
      this.selectTab(this.tabs.first);
    }
  }

  selectTab(tab: TabComponent) {
    this.tabs.toArray().forEach(tab => tab.active = false);
    tab.active = true;
    this.contentSbj.next(tab.contentRef);
  }
}
import {TabContentComponent} from './tab/tab-content.component'
import {TabContentAlternativeComponent} from './tab/tab-content-alternative.component'
...

@Component({
  selector: 'my-app',
  template: `
    <tab-container>
      <tab title="Tab 1" [contentRef]="normalContent"></tab>
      <tab title="Tab 2" [contentRef]="alternativeContent"></tab>
    </tab-container>
  `,
})
export class App {
  normalContent = TabContentComponent;
  alternativeContent = TabContentAlternativeComponent;
}
// Router.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
    {
        path: '',
        children: [
            { path: 'tab1', component: Tab1Component },
            { path: 'tab2', component: Tab2Component },
        ]
    },
    { path: '**', redirectTo: '' } // modify for default tab?
];


@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

export const routedComponents = [Tab1Component, Tab2Component];

// AppModule.ts
imports: [AppRoutingModule]
declarations: [
    routedComponents
],

// main.html
<app-header>
<us-tab-verticle>
<div class="tab" [routerLink]="['/tab1']"><a>
<div class="tab" [routerLink]="['/tab2']"><a>
<router-outlet></router-outlet> // the content of your tab components will be displayed below
<app-footer>