Angular2:用组件的模板替换宿主元素

Posted

技术标签:

【中文标题】Angular2:用组件的模板替换宿主元素【英文标题】:Angular2: replace host element with component's template 【发布时间】:2016-06-14 12:11:13 【问题描述】:

我是一般angular 和具体angular2 的新手。我正在尝试编写一个容器组件,其中应该有子组件。

例如容器组件

@Component(
  selector: 'my-list',
  template: `
    <ul>
      <ng-content></ng-content>
    </ul>
  `
)
export class MyList 

子组件:

import  Component  from 'angular2/core'

@Component(
  selector: 'my-item',
  template: `
    <li>
      <ng-content></ng-content>
    </li>
  `
)
export class MyItem 

我想做这个结构:

<my-list>
    <my-item>One</my-item>
    <my-item>Two</my-item>
</my-list>

要渲染到下面的:

<my-list>
    <ul>
        <li>One</li>
        <li>Two</li>
    </ul>
</my-list>

但是,相反,我保留了容器的宿主元素和项目:

<my-list>
    <ul>
        <my-item>
            <li>One</li>
        </my-item>
        <my-item>
            <li>Two</li>
        </my-item>
    </ul>
 </my-list>

Plunk is available here

问题:有没有办法消除宿主元素,只留下渲染的模板?

【问题讨论】:

见plnkr.co/edit/7nMTnH?p=preview @EricMartinez,在您的笨拙中,我看到您将 my-listmy-item 的用法替换为直接使用 ulli。这是没有意义的。我的意思是my-listmy-item 是组件,它们相应地呈现为ulli。当然,这只是一个非常简化的例子。实际情况要复杂得多,但重点还是一样的:消除(替换)宿主元素 【参考方案1】:

这你应该得到你想要的:

@Component(
  selector: 'ul[my-list]',
  template: `
    <ng-content></ng-content>
  `
)
export class MyList 

@Component(
  selector: 'li[my-item]',
  template: `
    <ng-content></ng-content>
  `
)
export class MyItem 
...

<ul my-list>
    <li my-item>One</li my-item>
    <li my-item>Two</li my-item>
</ul my-list>

【讨论】:

这会起作用,但这不是我所需要的。这会导致我的组件的用户知道我的实现 DOM 结构 (ul/li) - 让我在将来更改此结构时变得不那么灵活(例如更改为 div) 你可以做的是不要使用ulli,而是使用my-item和CSS my-item: display: list-item;,那么它的行为就像一个列表项,但不必是一个和你可以使用您在问题中使用的元素选择器(但使用我的答案的模板内容) 使用 CSS 可能还有另一个问题:我想使用现有的 bootstrap CSS 并能够顺利更新它。有没有办法为ulli 重用bootstrap 的样式并将它们应用于自定义元素? 当然,但只有当它们实际上是 &lt;ul&gt;&lt;li&gt; 元素时,就像我的回答中那样,而不是像在您的问题或我之前的评论中那样使用时。 @GünterZöchbauer - 这个解决方案有替代方案吗?我尝试复制您提供的代码,但它不起作用。谢谢。【参考方案2】:

最后我找到了解决方案:将ElementRef 注入MyItem 并使用它的nativeElement.innerhtml

我的列表

import  Component, ContentChildren, QueryList  from 'angular2/core'
import  MyItem  from './myitem'

@Component(
  selector: 'my-list',
  template: `
    <ul>
      <li *ngFor="#item of items" [innerHTML]="item.innerHTML"></li>
    </ul>
  `
)
export class MyList 
  @ContentChildren(MyItem) items: QueryList<MyItem>

我的物品:

import  Directive, Inject, ElementRef  from 'angular2/core'

@Directive(selector: 'my-item')
export class MyItem 
  constructor(@Inject(ElementRef) element: ElementRef) 
    this.innerHTML = element.nativeElement.innerHTML
  

Working plunk is here

【讨论】:

@Natanael,你可以在这里找到一个有效的 plunk:plnkr.co/edit/um5BC7?p=preview @Natanael 您必须在 ngAfterContentInit 回调中访问 innerHTML。如果您在构造函数中访问它,它是空的。我编辑了答案以反映这一点... 公平警告:不要将 InnerHTML 用于 static HTML 以外的任何内容。这包括绑定、其他组件等等——它会搞砸的【参考方案3】:

新的 Angular 版本具有非常酷的指令,也可以用于您的用例。多田:NgComponentOutlet。快乐编码 ;)

例子:

@Component(selector: 'hello-world', template: 'Hello World!')
class HelloWorld 


@Component(
  selector: 'ng-component-outlet-simple-example',
  template: `<ng-container *ngComponentOutlet="HelloWorld"></ng-container>`
)
class NgTemplateOutletSimpleExample 
  // This field is necessary to expose HelloWorld to the template.
  HelloWorld = HelloWorld;

【讨论】:

还有有趣的变化NgTemplateOutlet.. 这个为我做了这件事:) 请提供使用示例 @StevenLiekens 示例在文档中,但我在这里复制了它.. 使用了 ng-container 元素,这是在编译期间替换的元元素。 我的意思是你能展示如何使用 NgComponentOutlet 解决提问者的问题吗?【参考方案4】:

在最新的 Angular 中,您甚至可以避免添加 &lt;ng-content&gt;&lt;/ng-content&gt;

我申请的是这样的:

import Component from '@angular/core';

@Component(
    selector: 'div[app-root]',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css']
)
export class AppComponent 
    title = 'Delegates Presence Reporting';

和模板:

<div class="centered">
<h1>title</h1>
</div>

index.html

<body>
<div app-root></div>
</body>

【讨论】:

什么都没有被替换。输出将是 div app-root 内的 div class="centered"。

以上是关于Angular2:用组件的模板替换宿主元素的主要内容,如果未能解决你的问题,请参考以下文章

angular2 指令可以访问它所应用的组件的模板吗?

移除 Angular 组件创建的宿主 HTML 元素选择器

如何在angular2和ionic2中同时保留组件的DOM元素和模板字符串

模板中的Angular 2重复组件引用另一个元素

在循环中呈现 2 个 tr 元素的 Angular2 组件

如何使用 @hostbinding 为 Angular 2 中的宿主元素提供类