Angular:使用ComponentFactoryResolver进行组件的动态实例化,在SVG内部渲染

Den*_*ich 7 html svg angular

我有一个呈现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;
}
Run Code Online (Sandbox Code Playgroud)

当我静态实例化它时,一切正常(文本在页面上可见):

<svg>
  <svg:g hello name="Static component"></svg:g>
</svg>
Run Code Online (Sandbox Code Playgroud)

生成以下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>
Run Code Online (Sandbox Code Playgroud)

当我尝试使用ComponentFactoryResolver动态实例化组件时,问题就开始了:

<svg>
  <ng-container #container></ng-container>
</svg>
Run Code Online (Sandbox Code Playgroud)
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'
  }
}
Run Code Online (Sandbox Code Playgroud)

产生的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>
Run Code Online (Sandbox Code Playgroud)

请参阅stackblitz上的复制

JeB*_*JeB 7

我假设这里有两个问题:

  1. 如何使其运作?
  2. 为什么会这样呢?

第一个问题的答案是使用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; }`]
})
Run Code Online (Sandbox Code Playgroud)

app.component.html

<svg>
  <svg hello name="Static component"></svg>
</svg>
Run Code Online (Sandbox Code Playgroud)

现在让我们来看第二个问题。为什么会这样呢?
您的选择器不包含svg名称空间。为了正确呈现它,选择器应为svg:g[hello]
但是,由于一个老问题是一直存在,因为角5是不可能的
更多细节在这里这里

评论中所述,这里的主要问题是Angular选择器不能包含用于创建元素的名称空间。
选择器svg:g[hello]将解析为g[hello],结果Angular将使用document.createElement而不是document.createElementNS创建新元素。

为什么要使用svg[hello]作品?
因为如果我们使用选择器,svg[hello]则会将其解析到<svg child>Angular 隐式提供的名称空间

'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
Run Code Online (Sandbox Code Playgroud)