4

我正在尝试改进我的代码而不是有条件,所以我决定创建一个指令或可能的话创建一​​个管道,这可以帮助我根据其类型(字符串或模板引用)打印选项卡的标题,我的代码如下,此代码用于我的 Tabs/Tab 组件,也用于我的 Stepper/step 组件,所以我相信创建可重用的东西会很棒。我试过用 ElementRef、Renderer2、ViewContainerRef、TemplateRef 来做这件事……但我没有成功。

<ng-container *ngIf="tab.isLabelTemplate">
     <ng-container *ngTemplateOutlet="tab.title">
     </ng-container>
</ng-container>
<ng-container *ngIf="!tab.isLabelTemplate">{{ tab.title }}</ng-container>

isLabelTemplate 看起来像这样:

get isLabelTemplate(): boolean {
  return this.title instanceof TemplateRef;
}

非常感谢 :)

4

2 回答 2

3

您可以利用 Angular 低级 API 来动态操作 DOM 的结构:

这是该指令的外观示例:

标题模板.directive.ts

import { Directive, TemplateRef, Renderer2, ViewContainerRef, Input } from '@angular/core';

@Directive({
  selector: '[titleTemplate]',
})
export class TitleTemplateDirective {
  @Input()
  set titleTemplate(value: string | TemplateRef<any>) {
    this.updateView(value);
  }

  textNode: Text;

  constructor(private vcRef: ViewContainerRef, private renderer: Renderer2) {}

  private updateView(value: string | TemplateRef<any>) {
    this.clear();

    if (!value) {
      return;
    }

    if (value instanceof TemplateRef) {
      this.vcRef.createEmbeddedView(value);
    } else {
      this.textNode = this.renderer.createText(value);
      const elem = this.vcRef.element.nativeElement;

      this.renderer.insertBefore(elem.parentNode, this.textNode, elem);
    }
  }

  private clear() {
    this.vcRef.clear();
    if (this.textNode) {
      this.renderer.removeChild(this.textNode.parentNode, this.textNode);
    }
  }

  ngOnDestroy() {
    this.clear();
  }
}

用法:

<ng-container [titleTemplate]="title"></ng-container>  

分叉的 Stackblitz

于 2020-01-08T20:01:31.927 回答
2

或者您可以将此逻辑移动到“帮助”组件并在您的 TabComponent 中使用它。所以这个逻辑在一个地方(DRY)。辅助组件 (TitleComponent) 与您在 TabComponent 中使用的相同。这样,您只需移动“问题”,而不必一次又一次地重复。而且它仍然很容易阅读。

...
import { Component, Input, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-title',
  template: `
    <ng-container *ngIf="isLabelTemplate">
      <ng-container *ngTemplateOutlet="title">
      </ng-container>
    </ng-container>
    <ng-container *ngIf="!isLabelTemplate">{{ title }}</ng-container>
  `,
})
export class TitleComponent  {
  @Input() title: string | TemplateRef<any>;

  get isLabelTemplate(): boolean {
    return this.title instanceof TemplateRef;
  }
}


@Component({
  selector: 'app-tab',
  template: `
    <app-title [title]="title"></app-title>
  `,
})
export class TabComponent  {
  @Input() title: string | TemplateRef<any>;
}

...
于 2020-01-08T20:11:21.277 回答