使用 ng-content 时如何消除内部组件

How to eliminate inner component when using ng-content

我正在尝试排除弹出菜单,所以我可以这样写:

<panel-menu>
  <panel-menu-item>Edit input</panel-menu-item>
  <panel-menu-item>Edit mappings</panel-menu-item>
  <panel-menu-item divider-before>Show agent code</panel-menu-item>
</panel-menu>

我有一个 panel-menu 组件 HTML:

<div class="btn-group" [class.open]="...">
  <button type="button" class="btn btn-default" (click)="..."><i class="ion-gear-b icon-lg"></i></button>
  <ul class="dropdown-menu dropdown-menu-right">
    <ng-content select="panel-menu-item"></ng-content>
  </ul>
</div>

panel-menu-item与此HTML:

<li *ngIf="dividerBefore" class="divider"></li>
<li><a><ng-content></ng-content></a></li>

问题是结果 DOM 在 ulli 之间有一个 panel-menu-item,这打破了 third-party CSS.

有什么方法可以只投影所选 children 的 内容 ,而不投影 children 本身?

This answer 建议在 li 上使用属性而不是组件,但这会泄漏实现。 panel-menu 的用户不需要知道菜单项的实现元素。

要仅投影内容,您应该将内容包装在嵌入式视图中,例如:

面板菜单-item.component.ts

@Component({
  selector: 'panel-menu-item',
  template: `
    <ng-template>
      <li *ngIf="dividerBefore" class="divider"></li>
      <li><a><ng-content></ng-content></a></li>
    </ng-template>
  `
})
export class PanelMenuItemComponent {
  @ViewChild(TemplateRef) content: TemplateRef<any>;
}

在前面的代码中,我将模板包装在 ng-template 标记中,并使用 @ViewChild 装饰器从中获取 TemplateRef 实例。

有了 TemplateRef 我们可以轻松管理插入模板的位置:

面板-menu.component.ts

@Component({
  selector: 'panel-menu',
  template: `
    <div class="btn-group" >
      <button type="button" class="btn btn-default">Some button</button>
      <ul class="dropdown-menu dropdown-menu-right">
        <ng-container *ngFor="let item of menuItems">
          <ng-container *ngTemplateOutlet="item.content"></ng-container>
        </ng-container>
      </ul>
    </div>
  `
})
export class PanelMenuComponent {
  @ContentChildren(PanelMenuItemComponent) menuItems: QueryList<PanelMenuItemComponent>;

  constructor(private cdRef: ChangeDetectorRef) {}

  ngAfterViewInit() {
    this.cdRef.detectChanges();
  }
}

我正在使用 @ContentChildren 获取我们的面板菜单项,然后使用内置指令 NgTemplateOutlet 将内容放入 ul

我们必须使用 this.cdRef.detectChanges(); 运行 第二个摘要循环,因为我们会得到错误

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.

一旦 @ViewChild(TemplateRef) content 在更改检测期间更新其值。

Stackblitz Example