158

我正在尝试ng-content在 Angular 6 中使用多个构建自定义组件,但这不起作用,我不知道为什么。

这是我的组件代码:

<div class="header-css-class">
    <ng-content select="#header"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="#body"></ng-content>
</div>

我正在尝试在另一个地方使用这个组件,并在内部body和标题select中呈现两个不同的 HTML 代码ng-content,如下所示:

<div #header>This should be rendered in header selection of ng-content</div>
<div #body>This should be rendered in body selection of ng-content</div>

但是该组件呈现空白。

你们知道我可能做错了什么或者在同一个组件中呈现两个不同部分的最佳方法是什么?

谢谢!

4

6 回答 6

296
  1. 您可以添加虚拟属性headerbody而不是模板引用(#header, #body)
  2. 并使用ng-contentwithselect属性进行嵌入select="[header]"

app.comp.html

<app-child>
    <div header >This should be rendered in header selection of ng-content</div>
    <div body >This should be rendered in body selection of ng-content</div>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="[header]"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="[body]"></ng-content>
</div>

演示

于 2018-10-04T11:30:13.033 回答
80

符合Web 组件规范。即使那是Angular。这是关于避免选择器的属性,如 Angular 指令或保留属性用于其他用途。所以,我们只使用“slot”属性。我们将<ng-content select="[slot=foobar]">看到<slot name="foobar">.

例子:

你好-world.component.html

<ng-content select="[slot=start]"></ng-content>
<span>Hello World</span>
<ng-content select="[slot=end]"></ng-content>

app.component.html

<app-hello-world>
  <span slot="start">This is a </span>
  <span slot="end"> example.</span>
</app-hello-world>

结果

This is a Hello World example.

Stackblitz 示例

您可以使用任何您想要的名称,例如“banana”或“fish”。但是“开始”和“结束”是在前后放置元素的好习惯。

于 2020-01-23T14:11:02.853 回答
15

或者,您可以使用:

app.comp.html

<app-child>
    <div role="header">This should be rendered in header selection of ng-content</div>
    <div role="body">This should be rendered in body selection of ng-content</div>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="div[role=header]"></ng-content>
</div>
<div class="body-css-class">
    <ng-content select="div[role=body]"></ng-content>
</div>
于 2019-06-26T08:14:37.247 回答
7

补充其他答案:

您也可以使用自定义标签(如<ion-card><ion-card-header><ion-card-content>)来做到这一点。

app.comp.html

<app-child>
    <app-child-header>This should be rendered in header selection of ng-content</app-child-header>
    <app-child-content>This should be rendered in content selection of ng-content</app-child-content>
</app-child>

child.comp.html

<div class="header-css-class">
    <ng-content select="app-child-header"></ng-content>
</div>
<div class="content-css-class">
    <ng-content select="app-child-content"></ng-content>
</div>

您会收到一条警告消息,但它会起作用。您可以隐藏警告消息或使​​用已知标签,例如headerfooter。但是,如果您不喜欢这些方法中的任何一种,则应该使用其他解决方案之一。

于 2020-06-24T23:02:59.333 回答
4

作为另一种选择,您可以将模板传递给子组件,然后您将受益于能够将值绑定到内容/模板

父组件html

<app-child
    [templateHeader]="header"
    [templateContent]="content">
</app-child>

<ng-template #header
     let-data="data"> < -- how you get dynamic data
     what ever you would like the header to say
     {{data}}
</ng-template>

<ng-template #content>
    what ever you would like the content to say or any other component
</ng-template>

子组件 ts

export class ChildComponent {
    @Input() templateHeader: TemplateRef<any>;
    @Input() templateContent: TemplateRef<any>;
}

子组件html

<div class="header-css-class">
    <ng-container
        *ngTemplateOutlet="
        templateHeader;
        context: {   , < -- if you want to pass data to your template
            data: data
        }">
    </ng-container>
</div>
<div class="content-css-class">
    <ng-container *ngTemplateOutlet="templateContent">
    </ng-container>
</div>

有关模板的更完整解释,请参阅这篇很棒的文章https://indepth.dev/posts/1405/ngtemplateoutlet

于 2021-01-27T19:00:44.323 回答
1

如果您只想“接受”多个组件,则可以使用:

<ng-content select="custom-component,a"></ng-content>

这接受自定义组件的元素以及锚 (a) 元素,并且不会更改顺序。

于 2021-04-16T10:42:15.927 回答