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-list
和 my-item
的用法替换为直接使用 ul
和 li
。这是没有意义的。我的意思是my-list
和my-item
是组件,它们相应地呈现为ul
和li
。当然,这只是一个非常简化的例子。实际情况要复杂得多,但重点还是一样的:消除(替换)宿主元素
【参考方案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) 你可以做的是不要使用ul
和li
,而是使用my-item
和CSS my-item: display: list-item;
,那么它的行为就像一个列表项,但不必是一个和你可以使用您在问题中使用的元素选择器(但使用我的答案的模板内容)
使用 CSS 可能还有另一个问题:我想使用现有的 bootstrap
CSS 并能够顺利更新它。有没有办法为ul
和li
重用bootstrap
的样式并将它们应用于自定义元素?
当然,但只有当它们实际上是 <ul>
和 <li>
元素时,就像我的回答中那样,而不是像在您的问题或我之前的评论中那样使用时。
@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 中,您甚至可以避免添加 <ng-content></ng-content>
我申请的是这样的:
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:用组件的模板替换宿主元素的主要内容,如果未能解决你的问题,请参考以下文章