【问题标题】:How to create an SVG component dynamically in Angular2?如何在 Angular2 中动态创建 SVG 组件?
【发布时间】:2016-12-07 22:33:45
【问题描述】:

我正在创建一个使用 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 > @ 987654334@.

我也尝试使用selector='svg:svg[foo]',然后创建svg:svg 元素并显示它。但是svg:svg 不能与transform 属性一起移动,所以这对我的应用程序不起作用。

如何为属性选择器组件动态创建svg:g 元素?

我正在使用 Angular2:2.0.0-rc4。

【问题讨论】:

标签: svg angular


【解决方案1】:

关于保持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 中。

    【讨论】:

      【解决方案3】:

      我不会尝试使用组件解析器将组件创建到视图中。

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

      希望它清楚并解决您的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-11
        • 2017-07-21
        • 1970-01-01
        • 1970-01-01
        • 2017-11-01
        • 2017-04-27
        相关资源
        最近更新 更多