【问题标题】:Angular - Injecting component instance into the view of another componentAngular - 将组件实例注入另一个组件的视图
【发布时间】:2017-12-09 18:21:24
【问题描述】:

我正在使用 Angular 创建选项卡控件。结果应如下所示:

<tabs>
   <tab header="tab 1">
     hello
   </tab>
   <tab header="tab 2">
     world
   </tab>
</tabs>

现在,tab 组件看起来像这样:

@Component({
    selector: 'tab',
    template: `<ng-content></ng-content>`
})
export class TabComponent {
    @Input() header: string;
}

tabs 组件看起来像这样:

@Component({
    selector: 'tabs',
    template: `
       <div class="tabs">
            <ul>
                <li *ngFor="let tab of tabs">
                    <a (click)="selectTab(tab)">
                        {{tab.header}}
                    </a>
                </li>
            </ul>
        </div>
    `,
})
export class TabsComponent {
    @ContentChildren(TabComponent) tabs;

    selectTab(tab: TabComponent) {

    }
 }

现在,当调用 selectTab() 方法时,我希望将按下的选项卡(“hello”或“world”)的内容呈现在模板的底部。

TabsComponent中基本上需要有某种选项卡占位符,并且需要绑定到当前选中的TabComponent

无论如何,我无法让它工作。我尝试过使用 ng-templatecreateEmbeddedView,但我不明白如何从组件中获取 TemplateRef,而且我不完全确定这是正确的路要走。

先谢谢了!

【问题讨论】:

  • 为什么TabsComponent 模板中没有ng-content
  • 因为那时所有的标签都会出现在那里,而我只希望出现 selected 标签。
  • 如果你不使用它,Angular 会忽略 &lt;tabs&gt;content ignored&lt;/tabs&gt; 标签内的所有内容。
  • 这不准确,因为我使用的是 ContentChildren 装饰器。它检索选项卡内的所有 TabComponent,然后由 TabsComponnet 使用以生成选项卡标题。当用户按下选项卡标题时,我想显示相关的 TabComponent
  • 对,您可以通过ContentChildren 访问它们。 tabcompoennt 内容到底需要什么?现在它只是文本,你需要那个文本吗?你能添加这样的模板引用吗&lt;tab&gt;&lt;span #t&gt; hello&lt;/span&gt;&lt;/tab&gt;

标签: javascript angular typescript


【解决方案1】:

好的,所以我解决了,但我不确定这是正确的解决方案。 我重复我的需求: 我想制作一个功能齐全的选项卡集组件,它由选项卡标题和当前选定的选项卡组成。

示例: https://s3.envato.com/files/169665336/Thetabs%20-%20Responsive%20HTML5%20&%20CSS3%20Tabs%202016-01-29%2005-57-05.png

所以这是我的解决方案。请随时提出更好的建议,因为我不完全确定这是选项卡集组件的示例:

@Directive({
    selector: 'tab',
})
export class TabDirective {
    private static seed = 0;

    readonly id: number;

    @Input() header: string;

    @HostBinding('hidden') isHidden: boolean;

    private isActive: boolean;
    @HostBinding('class.active') set active(value: boolean) {
        this.isActive = value;
        this.isHidden = !this.isActive;
    }

    get active(): boolean {
        return this.isActive;
    }

    constructor() {
        this.id = TabDirective.seed++;
        this.active = false;
    }
}

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

        <ng-content></ng-content>
    `,
})
export class TabsComponent implements AfterViewInit {
    @ContentChildren(TabDirective) tabs: QueryList<TabDirective>;

    @Output() select = new EventEmitter<TabDirective>();

    private selectedTab: TabDirective;

    selectTab(tab: TabDirective) {
        this.tabs.forEach((t: TabDirective) => t.active = (t.id === tab.id));
        this.selectedTab = tab;
    }

    ngAfterViewInit(): void {
        if (this.tabs && this.tabs.length > 0) {
            this.tabs.first.active = true;
        }
    }
}

@Component({
    template: `
        <tabs>
            <bu-tab header="hello">
                Hello!!
            </bu-tab>
            <bu-tab header="world">
                World!!
            </bu-tab>
        </tabs>
  `,
})
export class App { }

【讨论】:

  • 您好 Eliran,您能发布完整的代码示例吗?
猜你喜欢
  • 2017-06-17
  • 2018-12-31
  • 2019-06-15
  • 2017-07-23
  • 2019-12-08
  • 2020-01-10
  • 2023-01-12
  • 1970-01-01
  • 2017-10-01
相关资源
最近更新 更多