【问题标题】:Manipulating unrendered DOM elements for export in Angular操作未渲染的 DOM 元素以在 Angular 中导出
【发布时间】:2020-07-26 06:27:37
【问题描述】:

我创建了一个 Angular 服务来为用户导出一个 SVGElement。简而言之,它构建了一个 SVG 并将符号附加到 <defs>。然后,服务使用 Promise 将此 SVG 返回给组件,组件将其复制到剪贴板或将其导出为文件。

我的问题是导出的 SVG 元素在组件尝试导出它时为空。如果我在服务中的resolve(svgElement) 周围插入一个setTimeout(),它就可以工作。

如何以更同步的方式操作这些动态生成的 DOM 元素? SVG 永远不会为用户呈现。

这里有一些简化的代码来尝试说明功能。

\\ service.ts
public exportToSVG(ids: string[]): Promise<SVGElement> {
   return new Promise((resolve, reject) => {
      const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      const defs = document.createElement('defs');

      ids.forEach(async id => {
         // use another method to get the symbol associated with the id
         const symbol = await this._getSymbolByString(id);
         defs.appendChild(symbol);
      });

      svg.appendChild(defs);
      resolve(svg);
   });
}

\\ component.ts
public copyToClipboard(ids: string[]) {
   this.myService.exportToSVG(ids).then(svg => {
      // this only copies `<svg><defs></defs></svg>`, unless a setTimeout is used
      this.clipboardService.copyFromContent(svg.outerHTML);
   });
}

【问题讨论】:

  • 符号存储在其他地方,这只是通过给定的字符串抓取一个,假设它返回一个 SVGSymbolElement
  • 该代码实际上返回了一个 Promise,我可以编辑帖子。我可能过多地简化了提供的代码,但不幸的是无法提供太多细节。我在返回 Promises 的不同代码段上尝试了 async... awaits 的多种变体,但似乎唯一可行的是 setTimeout()

标签: javascript angular svg dom


【解决方案1】:

尝试使用innerHTML:

\\ component.ts
public copyToClipboard(ids: string[]) {
   this.myService.exportToSVG(ids).then(svg => {
      this.clipboardService.copyFromContent(svg.innerHTML);
   });
}

【讨论】:

    【解决方案2】:

    Angular 具有异步特性。当您应用 Foreach 循环时,角度不等待响应并执行下一个操作,这就是您无法获得 defs 变量的原因。您应该将此代码放入 foreach 循环完成后触发的条件中。

    \\ service.ts
    public exportToSVG(ids: string[]): Promise<SVGElement> {
       return new Promise((resolve, reject) => {
          const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
          const defs = document.createElement('defs');
          let lengthIds = is.length;
          let count = 0;
    
          ids.forEach(async id => {
             // use another method to get the symbol associated with the id
             const symbol = await this._getSymbolByString(id);
             defs.appendChild(symbol);
             count++;
          });
      
        // check length of total number of elements in array and its count
          if(count === lengthIds){
            svg.appendChild(defs);
            resolve(svg);
          }
         
       });
    }
    
    \\ component.ts
    public copyToClipboard(ids: string[]) {
       this.myService.exportToSVG(ids).then(svg => {
          // this only copies `<svg><defs></defs></svg>`, unless a setTimeout is used
          this.clipboardService.copyFromContent(svg.outerHTML);
       });
    }

    所以我认为它对你有用。

    【讨论】:

      【解决方案3】:

      我通过链接 Promises 解决了这个问题,而不是使用 async...await。

      【讨论】:

        猜你喜欢
        • 2017-05-16
        • 1970-01-01
        • 2015-09-17
        • 2022-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-25
        • 1970-01-01
        相关资源
        最近更新 更多