如何在Angular2中动态创建SVG组件?

5

我正在创建一个使用SVG的Web应用程序。 我创建了由SVG元素组成的组件,并将它们放入根svg元素中。 它们具有属性选择器,因为SVG/XML文档树是严格的,所以我无法使用元素选择器。 它们具有一个以svg:g标签开头的模板:

@Component({
  selector:'[foo]',
  template: '<svg:g>...</svg:g>',
})

在应用程序中,当用户按下按钮时,我希望创建一个组件,并同时开始拖动它。 我认为可以通过使用ComponentResolver动态地创建组件来实现:

  @ViewChild('dynamicContentPlaceHolder', {read: ViewContainerRef})
  protected dynamicComponentTarget: ViewContainerRef

  private componentResolver: ComponentResolver

  onMouseDown() {
    this.componentResolver
      .resolveComponent(FooComponent)
      .then((factory) => {
        const dynamicComponent = this.dynamicComponentTarget.createComponent(factory, 0)
        const component: FooComponent = dynamicComponent.instance
        const element = dynamicComponent.location.nativeElement
        // add event listener to start dragging `element`.
      })
  }

当调用onMouseDown()时,组件被创建,但它的DOM元素是div,因此它在svg文档中是非法元素,无法显示。
我尝试使用selector='svg:g[foo]',然后创建了g元素,但它的命名空间不是SVG(http://www.w3.org/2000/svg),而是普通HTML命名空间(http://www.w3.org/1999/xhtml),其类是HTMLUnknownElement>g
我还尝试使用selector='svg:svg[foo]',然后创建svg:svg元素,并且它被显示。但是svg:svg不能使用transform属性移动,因此这对我的应用程序效果不佳。
如何为属性选择器组件动态创建svg:g元素?
我正在使用Angular2:2.0.0-rc4。

听起来像是 https://github.com/angular/angular/issues/10404 - Günter Zöchbauer
谢谢,@GünterZöchbauer!问题与我想尝试的相同。感谢您的信息。我正在等待解决方案/错误修复。 - tyfkda
3个回答

5

你对命名空间问题的看法是正确的,这也是导致 g 元素不能呈现为 svg 的原因。不幸的是,将节点作为 svg 元素附加是使组件合理命名空间化的唯一方式。

然而,这并不意味着它行不通。如果在模板中将拖动功能作为指令添加到 g 元素上,则会将其编译到您的组件中,并且您可以将逻辑偏移至该指令中。顶级 svg 将被正确命名空间化,模板将相应地继承这一点。

import {Component, Input} from '@angular/core';

@Component({
  selector: 'svg:svg[customName]', // prevent this from hijacking other svg
  template: '<svg:g dragDirective>...</svg:g>', // note the directive added here
  style: []
})
export class GComponent {

  constructor() { }

}

这可能不是最理想的,但在https://github.com/angular/angular/issues/10404得到解决之前,没有太多替代选择。

2

我不确定我的解决方案是否正确,但它对我有效(即使使用 ivy):

@Component({
...
})
class ParentComponent {
    constructor(
        private injector: Injector,
        private appRef: ApplicationRef,
        private componentFactoryResolver: ComponentFactoryResolver,
    ) {}

    createDynamicComponent() {
        let node = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        let factory = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
        let componentRef = factory.create(this.injector, [], node);

        this.appRef.attachView(componentRef.hostView);
    }
}

之后,您必须手动将node添加到DOM中。


0

不要试图使用组件解析器将您的组件创建到视图中,我会选择另一种方法。

  • 创建一个对象,其属性与要传递给SVG组件的属性相匹配。
  • 将此对象附加到数组中(例如svgItems)。
  • 将*ngFor="svgItem in svgItems"添加到要动态创建的SVG组件中。

希望这很清楚并解决了您的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接