移除 Angular 组件创建的宿主 HTML 元素选择器
Posted
技术标签:
【中文标题】移除 Angular 组件创建的宿主 HTML 元素选择器【英文标题】:Remove the host HTML element selectors created by angular component 【发布时间】:2016-03-20 17:27:10 【问题描述】:在 Angular 2 中,svg-rect 是一个创建 rect 的组件,如下所示,
<svg x="0" y="0">
<g id="svgGroup">
<svg-rect>
<!--template bindings=-->
<rect x="10" y="10" fill="red" stroke="#000" stroke-></rect>
<!--template bindings=-->
</svg-rect>
<svg-rect>
<!--template bindings=-->
<rect x="10" y="10" fill="red" stroke="#000" stroke-></rect>
<!--template bindings=-->
</svg-rect>
</g>
</svg>
但这不会渲染 rect 因为创建了特殊的元素标签。如果 svg-rect 标签被移除,它会呈现 rect
<svg x="0" y="0">
<g id="svgGroup">
<!--template bindings=-->
<rect x="10" y="10" fill="red" stroke="#000" stroke-></rect>
<!--template bindings=-->
<!--template bindings=-->
<rect x="10" y="10" fill="red" stroke="#000" stroke-></rect>
<!--template bindings=-->
</g>
</svg>
在 Angular 1.x 中,有 replace: 'true' 可以删除带有编译输出的指令标签。我们可以在 angular2 中实现相同的功能吗?
【问题讨论】:
【参考方案1】:与其尝试摆脱宿主元素,不如将其转换为有效的 SVG 但在其他方面不受影响:而不是您的 元素选择器
selector: "svg-rect"
及其在模板中对应的元素:
template: `...<svg-rect>...</svg-rect>...`
切换到属性选择器:
selector: "[svg-rect]"
并将该属性添加到组元素标记中:
template: `...<g svg-rect>...</g>...`
这将扩展为:
<svg x="0" y="0">
<g id="svgGroup">
<g svg-rect>
<!--template bindings=-->
<rect x="10" y="10" fill="red" stroke="#000" stroke-></rect>
<!--template bindings=-->
</g>
<g svg-rect>
<!--template bindings=-->
<rect x="10" y="10" fill="red" stroke="#000" stroke-></rect>
<!--template bindings=-->
</g>
</g>
</svg>
这是有效的 SVG,它将被渲染。 Plnkr
【讨论】:
这适用于任何需要有效元素的地方,我刚刚将它用于出现相同问题的表头另一种删除我使用的组件主机的方法。
指令remove-host
//remove the host of avatar to be rendered as svg
@Directive(
selector: '[remove-host]'
)
class RemoveHost
constructor(private el: ElementRef)
//wait for the component to render completely
ngOnInit()
var nativeElement: htmlElement = this.el.nativeElement,
parentElement: HTMLElement = nativeElement.parentElement;
// move all children out of the element
while (nativeElement.firstChild)
parentElement.insertBefore(nativeElement.firstChild, nativeElement);
// remove the empty element(the host)
parentElement.removeChild(nativeElement);
使用该指令;<avatar [name]="hero.name" remove-host></avatar>
在remove-host
指令中,nativeElement
的所有子元素都插入到宿主之前,然后移除宿主元素。
Sample Example Gist根据用例,可能存在一些性能问题。
【讨论】:
可能是性能问题,这是我最初的想法。但是目前在我的材料设计轻组件中使用这种方式来替换宿主元素,否则会出现显示 html 的问题 @Kuncevich 很高兴知道我的回答有所帮助,当元素ChangeDetection
被触发为 shadow DOM !== actual DOM
时,会产生性能瓶颈。但是如果没有很多元素,那么这不会那么大。希望;)
我们需要一些Angular1的类比replace:true
***.com/questions/22497706/…有人说这个功能实际上是在angular2中但非官方支持的。
@Kuncevic 恰恰相反。它仍在 Angular1 中,但在那里已弃用。这就是为什么他们一开始不想在 Angular2 中添加它。事实证明,许多问题值得付出努力。
如果您考虑将这种技术与正在更改数据的ngFor
一起使用,您会惊讶于 UI 无法正确更新。【参考方案3】:
类似的东西呢:
:host display: contents;
将它放在宿主组件的 css(或 scss)文件中将导致组件的框不呈现。
N.B:它以前对我有用——但显然我会担心浏览器的兼容性,特别是如果您正在开发以支持旧浏览器。我也很确定这并不完全超出“实验”阶段。文档还指出,这可能会导致可访问性问题。
【讨论】:
这样一个简短、简单、有效的答案 这很好用,没有额外的解决方法。希望 Angular 会在某个时候添加不呈现宿主元素的选项。 这对我不起作用。也许他们在较新版本的 Angular 中删除了此功能。 如果有选择器期望直接后代,这不一定有效。 虽然没有删除父元素,但至少不会在视觉上修改您的布局。【参考方案4】:还有另一种方法,我们可以从组件中获取组件的模板。 首先,我们创建组件,我们希望从浏览器渲染中移除它的标签(我们不是在这里试图移除标签。)
@Component(
selector: 'tl-no-tag',
template: `
<template #tmp>
<p>value</p>
</template>`,
styleUrls: []
)
export class TlNoTagComponent
@ViewChild('tmp') tmp: any;
value = 5;
然后,在另一个组件的模板中,我们写:
<tl-no-tag #source></tl-no-tag> <!-- This line can be placed anywhere -->
<template [ngTemplateOutlet]="source.tmp"></template> <!-- This line will be placed where needed -->
然后,我们在浏览器中有这样的东西:
<tl-no-tag></tl-no-tag>
<p>5</p>
所以,我们将<p>value</p>
带出TlNoTagComponent。 <tl-no-tag></tl-no-tag>
将继续存在,但不会阻止任何 css 或 svg-thing。
【讨论】:
"模板是否有自己独立的变量作用域,模板能看到哪些变量?"看看这个(在模板内容部分):blog.angular-university.io/… 如果您要使用*ngFor
来处理这些数据,这就是您要走的路。我的方案是将<td>
组合在一起。此代码完美运行。确保在tl-no-tag
上设置display: none
,这样它就不会干扰您的colspan
。【参考方案5】:
引用Angular 1 to Angular 2 Upgrade Strategy doc:
Angular 2 不支持替换其宿主元素的指令(在 Angular 1 中替换为 true 指令)。在许多情况下,这些指令可以升级为常规组件指令。
在某些情况下,常规组件指令不起作用,在这些情况下可以使用替代方法。例如对于 svg,请参见:https://github.com/mhevery/ng2-svg
【讨论】:
非常感谢您指出这一点。我确信在 Angular 中删除宿主元素是可能的,但这显然是我们在 AngularJS 时代使用的东西:以上是关于移除 Angular 组件创建的宿主 HTML 元素选择器的主要内容,如果未能解决你的问题,请参考以下文章