我有一个呈现DOM的组件,该组件应位于svg
标签内:
import { Component, Input } from '@angular/core';
@Component({
selector: 'g[hello]',
template: `<svg:text x="50%" y="50%" text-anchor="middle">Hello, {{name}}</svg:text>`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
@Input() name: string;
}
当我静态实例化它时,一切正常(文本在页面上可见):
<svg>
<svg:g hello name="Static component"></svg:g>
</svg>
将生成以下DOM:
<svg _ngcontent-iej-c129="">
<g _ngcontent-iej-c129="" hello="" name="Static component" _nghost-iej-c130="" ng-reflect-name="Static component">
<text _ngcontent-iej-c130="" text-anchor="middle" x="50%" y="50%">
Hello, Static component
</text>
</g>
</svg>
当我尝试使用ComponentFactoryResolver动态实例化组件时,问题就开始了:
<svg>
<ng-container #container></ng-container>
</svg>
import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, OnInit } from '@angular/core';
import { HelloComponent } from './hello.component'
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
@ViewChild('container', {read: ViewContainerRef, static: true}) container: ViewContainerRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
// Instantiating HelloComponent dynamically
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(HelloComponent)
const componentRef = this.container.createComponent(componentFactory);
componentRef.instance.name = 'Dynamic component'
}
}
产生的DOM看起来不错,但由于某些原因,文本在页面上不可见:
<svg _ngcontent-iej-c129="">
<!---->
<g hello="" _nghost-iej-c130="">
<text _ngcontent-iej-c130="" text-anchor="middle" x="50%" y="50%">
Hello, Dynamic component
</text>
</g>
</svg>
答案 0 :(得分:7)
我认为这里有两个问题:
第一个问题的答案是使用svg
而不是g
对元素进行分组。
在您的具体示例中,这意味着更改选择器:
@Component({
selector: 'svg[hello]',
template: `<svg:text x="50%" y="50%" text-anchor="middle">Hello, {{name}}</svg:text>`,
styles: [`h1 { font-family: Lato; }`]
})
还有app.component.html
:
<svg>
<svg hello name="Static component"></svg>
</svg>
现在让我们来看第二个问题。为什么会这样?
您的选择器不包含svg
命名空间。为了正确呈现它,选择器应为svg:g[hello]
。
但这是不可能的,因为自Angular 5起就存在一个古老的问题。
here和here的更多详细信息。
如this评论中所述,这里的主要问题是Angular选择器不能包含用于创建元素的名称空间。
选择器svg:g[hello]
将被解析为g[hello]
,因此Angular将使用document.createElement
而不是document.createElementNS
来创建新元素。
为什么使用svg[hello]
有用?
因为如果我们使用选择器svg[hello]
,它将被解析为<svg child>
,对于此标记,Angular为providing namespace implicitly:
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
答案 1 :(得分:2)
似乎与未解决的问题有关,请参见
答案 2 :(得分:2)
似乎与旧的Angular问题有关:#10404,也与Vitalii提到的问题有关:#20337
在#10404中,DingWeizhe提出了以下解决方法:
代替此代码:
const componentRef = this.container.createComponent(componentFactory);
要使用此功能:
const groupElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
const componentRef = componentFactory.create(injector, [], groupElement);
this.container.insert(componentRef.hostView)
此更改可解决问题,而无需将<g>
替换为<svg>
。可以接受的答案当然也可以解决问题,但是我担心性能下降会导致这种情况。
正在工作的堆叠闪电是here