Angular 2 在标题单击时动态加载选项卡



我使用 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>

问题是视图加载时所有选项卡组件都在加载。

我的选项卡实现如下。

us-tab-verticle.component.html

<div class="v-tabs">
<div class="v-tabs-col v-tabs-left">
<ul class="nav nav-v-tabs flex-column" role="tablist">
<li class="nav-v-item" *ngFor="let tab of tabs" (click)="selectTab(tab)">
<a [class.active]="tab.active" class="nav-v-link" data-toggle="tab" href="#" role="tab">{{tab.title}}</a>
</li>
</ul>
</div>
<div class="v-tabs-col v-tabs-fill">
<div class="v-tabs-content">
<div>
<ng-content></ng-content>
</div>
</div>
</div>

us-tab-verticle.component.ts

import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core';
import { VtabContentComponent } from './vtab-content/vtab-content.component';
@Component({
selector: 'us-tab-verticle',
templateUrl: './us-tab-verticle.component.html',
styleUrls: ['./us-tab-verticle.component.scss']
})
export class UsTabVerticleComponent implements AfterContentInit {
@ContentChildren(VtabContentComponent) tabs: QueryList<VtabContentComponent>;
// contentChildren are set
ngAfterContentInit() {
// get all active tabs
const activeTabs = this.tabs.filter((tab) => tab.active);
// if there is no active tab set, activate the first
if (activeTabs.length === 0) {
this.selectTab(this.tabs.first);
}
}
selectTab(tab: VtabContentComponent) {
// deactivate all tabs
this.tabs.toArray().forEach(tab => tab.active = false);
// activate the tab the user has clicked on.
tab.active = true;
}
}

vtab-content.component.html

<div class="tab-content v-tab-content align-content-stretch">
<div [hidden]="!active" class="tab-pane active" role="tabpanel">
<ng-content></ng-content>
</div>
</div>

vtab-content.component.ts

import { Component, Input } from '@angular/core';
import { NgComponentOutlet } from '@angular/common';
@Component({
selector: 'vtab-content',
templateUrl: './vtab-content.component.html',
styleUrls: ['./vtab-content.component.scss']
})
export class VtabContentComponent  {
@Input('tabTitle') title: string;
@Input() active = false;
}

当我单击每个选项卡的标题时,我需要加载每个组件。 我播种NgComponentOutlet可以使用这种情况。但不知道如何实施。

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

我建议你看看RouterModule使用children归因。

一个小示例:(不确定您可以立即使其工作,但我在我的应用程序中使用了类似的东西(

// 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>

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

我尝试使用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 {}

下面是带有选项卡呈现的选项卡容器组件和动态正文组件的空占位符:

@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;
}

这是工作的Plunkr

最新更新