【问题标题】:Multiple ng-content多个 ng 内容
【发布时间】:2019-03-09 08:57:50
【问题描述】:

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

这是我的组件代码:

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

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

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

但组件呈现空白。

你们知道我做错了什么吗,或者在同一个组件中渲染两个不同部分的最佳方法是什么?

谢谢!

【问题讨论】:

  • 对不起,stackoverflow 没有保存我的第二个代码 sn-p: 我在组件中使用的代码是这样的:
    这是标题内容
    这是正文内容

标签: angular angular6 angular-components ng-content


【解决方案1】:
  1. 您可以添加虚拟属性 headerbody,而不是模板引用 (#header, #body)
  2. 并使用带有select 属性的ng-content 进行转换,例如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>

DEMO

【讨论】:

  • 如果你不想渲染额外的 div 或任何其他标签,你应该使用
  • @AmitChigadani 我相信@sobczi 的意思是你可以用&lt;ng-container header&gt; 替换&lt;div header&gt;
  • 我确认用&lt;ng-container header&gt; 替换&lt;div header&gt; 也可以。
  • 对于任何想要了解更多细节的人,这被称为多槽内容项目(与单槽相反)。 Angular 文档有一些很好的例子:angular.io/guide/content-projection
【解决方案2】:

符合Web Component 规范。即使那是Angular。这是关于避免选择器的属性,如 Angular 指令或保留属性用于其他用途。所以,我们只使用“slot”属性。我们会将&lt;ng-content select="[slot=foobar]"&gt; 视为&lt;slot name="foobar"&gt;

例子:

hello-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 Example

您可以使用任何您想要的名称,例如“香蕉”或“鱼”。但是“开始”和“结束”是在前后放置元素的一个很好的约定。

【讨论】:

  • 如何查询这些元素?带名称槽。
  • 这取决于您的 Angular 和组件设置以及您真正想要的。您可以在 TS 中使用 ViewChild 或在 SCSS 中使用 :host::ng-deep。但这只是一个例子。 See Stackblitz 也许::slotted / ::content 也可以。但不确定。网络将提供有关此主题的更多信息。通常,您应该只设置组件本身的样式。并避免在外部(全局)样式化东西。否则你会产生不必要的副作用。
  • 一个好的做法是包装它。请参阅我上一条评论中更新的 Stackblitz 示例。查看组件的 html 和 css 文件。你应该更喜欢这个而不是 ng-deep。例如。 &lt;div class="end"&gt;&lt;ng-content&gt;&lt;/ng-content&gt;&lt;/div&gt; 因为这个元素在组件中是可访问的。 ng-content 只是一个伪元素,它被外部的停靠元素替换。所以你必须使用 ng-deep 选择器。
  • @Dominik 假设我需要知道“开始”插槽是否有内容,或者是否已定义。这可行吗?
  • @darksoulsong See example。这是一个检查元素是否有子元素的指令。 ...但是我建议您再考虑一下您是否真的需要它或是否有其他解决方案。 :)
【解决方案3】:

您也可以使用:

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>

【讨论】:

    【解决方案4】:

    补充其他答案:

    您也可以使用自定义标签(如&lt;ion-card&gt;&lt;ion-card-header&gt;&lt;ion-card-content&gt;)来实现。

    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。 但是,如果您不喜欢这些方法中的任何一种,您应该使用其他解决方案之一。

    【讨论】:

    • app-child-headerapp-child-content 必须定义角度分量。还是仅在 ng-content 选择属性中引用这些名称就足够了?
    • @KenHadden select 属性将接受将投影到ng-content 元素中的任何CSS selector 元素。因此,您可以将它用作this answer 中提到的@Dominik,就像我上面提到的那样,或者与任何本机HTML 元素(例如divspam)一起使用。您实际上可以使用将嵌套到 app-child 元素的元素的任何 CSS 选择器,如 ng-content docs 中所述
    【解决方案5】:

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

    父组件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

    【讨论】:

      【解决方案6】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-26
        • 2017-11-22
        • 2013-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多