【问题标题】:How to reach SVG elements by Angular ViewChildren如何通过 Angular ViewChildren 访问 SVG 元素
【发布时间】:2019-05-31 03:19:39
【问题描述】:

我有一个 svg 作为对象加载:

<object data="assets/img/states.svg" type="image/svg+xml" id="map"></object>

这个 svg 包含一个大 png 地图和几个矩形和文本元素。

<rect
     y="224.72084"
     x="644.87109"
     height="231.68137"
     width="101.08391"
     id="RECT_TO_GET" />

我想在一个数组中获取所有 rect 元素,就像我使用普通的 html 元素一样:

@ViewChildren('rect') rects !: QueryList<any>;
this.rects.forEach(r=> {
            console.log(r);
        });

问题是 rects 数组总是空的。我试图让它们进入ngViewAfterInit()ngAfterViewChecked(),但没有成功。如何访问 svg 的元素?

我还没有尝试通过getElementsById() 获得它们,如果可能的话,我想以有角度的方式进行。

整个事情就是在我得到每个矩形元素后为其提供上下文颜色。

【问题讨论】:

    标签: angular typescript dom svg


    【解决方案1】:

    ViewChildViewChildren 不支持 CSS 选择器

    https://angular.io/api/core/ViewChild

    支持的选择器包括:

    • 任何带有@Component 或@Directive 装饰器的类
    • 作为字符串的模板引用变量(例如,使用@ViewChild('cmp')` 进行查询)
    • 在当前组件的子组件树中定义的任何提供者(例如@ViewChild(SomeService) someService: SomeService)
    • 通过字符串令牌定义的任何提供程序(例如 @ViewChild('someToken') someTokenVal: any)
    • 一个 TemplateRef(例如使用 @ViewChild(TemplateRef) 模板查询;)

    您可以从模板引用变量中获取 HtmlElement,并在加载对象元素资源后开始尝试操作它

    online example

    html

      <object #mySvg data="./assets/new.svg" type="image/svg+xml" id="map"></object> 
    

    组件

      @ViewChild('mySvg') mySvg;
    
      ngOnInit() {
          const objElm = (this.mySvg.nativeElement as HTMLObjectElement);
        objElm.onload = () => {
            const paths = objElm.contentDocument.querySelectorAll('path');
    
            paths.forEach((path,index) => {
              console.log(`path:${index} , d=${path.getAttribute("d")}`);
            })
    
        }    
      }
    

    【讨论】:

    • 它不起作用,this.rects 只是一个空的 NodeList 数组。 mySvg 包含对象 html 元素,但它似乎是空的。
    • 更新到新版本,我在加载对象元素资源后操作 SVG 元素
    【解决方案2】:

    进行了更多研究并找到了以下解决方案。有趣的是,这段代码在我的角度组件的 ngAfterViewInit 方法中,它仍然需要 window.onload 事件监听器才能工作。为什么?

    window.addEventListener("load", function() {
        var svgObject = document.getElementById('map').contentDocument;
        var svg = svgObject.getElementById('svg48152');
        console.log(svg);
        const rects = svg.querySelectorAll('rect');
        console.log(rects);
        rects.forEach(r => {
            console.log(r);
        });
    });
    

    关键组件是contentDocument 属性和onload 事件监听器。一些有用的信息供将来参考:Using Javascript with SVG

    【讨论】:

    • 窗口加载事件只是确保您的 SVG(#map) 和主 DOM 在您开始尝试操作之前已加载
    【解决方案3】:

    我只是想在@Chunbin Li 给出的答案中添加一件小事(可悲的是,我目前没有足够的声誉发表评论)。无论如何,在 cmets 部分,@Perrier 说 this.rects 仍然是一个空节点列表。这可以通过使用不同的生命周期方法来解决。

    使用ViewChild 时,通常使用生命周期方法ngAfterViewInit()。在@Chunbin Li 的回答中,函数在ngOnInit() 中被调用,所以很可能SVG 没有足够的时间来渲染。如果您改为在 ngAfterViewInit() 中调用该函数,它将给 DOM 足够的时间来完全渲染 SVG,并且 SVG 的属性将可以访问。

    如需进一步阅读,请查看 ViewChild 上的 angular 文档。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      相关资源
      最近更新 更多