【问题标题】:Angular 10 Load SVG Dynamically Without IMG or OBJECT TagsAngular 10 在没有 IMG 或 OBJECT 标签的情况下动态加载 SVG
【发布时间】:2021-02-03 17:04:39
【问题描述】:

我正在研究一种无需使用 IMG 或 OBJECT 标记即可加载 SVG 文件的简化方法,因为它妨碍了我通过外部 CSS 控制填充颜色的能力。使用内联 SVG 是理想的,但是有这么多使用重复图标的组件,需要大量维护,我更愿意将它们集中在 .svg 文件格式中。我想过让每个组件都成为自己的组件,但这意味着我不需要每个组件都有一个 component.ts 文件,这可能会让其他开发人员感到有些困惑。

到目前为止,创建一个从“src”属性中提取 svg 位置的自定义元素是有效的:

@Component({
    selector: 'app-svg',
    template: `
        <ng-template>
            {{ src }}
        </ng-template>
        <span [innerHTML]="svg"></span>
    `
})
export class SvgComponent implements OnInit {
    svg: SafeHtml = '';
    @Input() public src = '';

    constructor(private http: HttpClient, private sanitize: DomSanitizer) {
    }

    ngOnInit(): void {
        this.http.get(this.src, {responseType: 'text'}).subscribe(svg => {
            this.svg = this.sanitize.bypassSecurityTrustHtml(svg);
        });
    }
}

然后我在另一个component.html中使用我的自定义元素:

<app-svg src="assets/test.svg"></app-svg>

结果当然是一个内联 SVG,内联元素作为包装器:

<app-svg src="assets/test.svg" ng-reflect-source="assets/test.svg">
   <span>
      <svg>
         <path d="...">
      </svg>
   </span>
</app-svg>

我想这是无害的,但它有点烦人,并且有不必要的额外标记。理想情况下,我希望将 innerHTML 应用于 APP-SVG,但这意味着由于范围问题,绑定中的 svg 需要存在于自定义元素的 TS 之外。必须记住在每个 APP-SVG 标记中包含 [innerHTML] 也很麻烦。我尝试在模板中的 SPAN 标记上使用 [outerHTML],但出现运行时错误,提示没有父容器元素。

所以,我的问题是这行得通吗?:

  1. 用加载的SafeHtml替换模板中的?或者,
  2. 将加载的 SafeHtml 应用为 SvgComponent TS 中选择器的 innerHTML?或者,
  3. 使用 作为模板的一部分而不是 SPAN,但在将父 SVG 从加载的 SafeHtml 应用到 innerHTML 之前删除它?或者,
  4. NPM 中有什么东西已经完成了我想要创建的功能吗?

我希望他们让这更容易。任何关于为什么这不起作用的建议或解释将不胜感激。谢谢!

【问题讨论】:

    标签: html angular svg httpclient element


    【解决方案1】:

    自然,我一发布我的问题,就会被解决方案绊倒。诀窍是使用 ElementRef 以便我可以定位选择器的 innerHTML,而我不必使用 DomSanitizer 来执行此操作。新代码如下(包括这次的导入):

    import {Component, OnInit, Input, ElementRef} from '@angular/core';
    import {HttpClient} from '@angular/common/http';
    
    @Component({
        selector: 'app-svg',
        template: `
            <ng-template>
                {{ src }}
            </ng-template>
        `
    })
    export class SvgComponent implements OnInit {
        @Input() public src = '';
    
        constructor(
            private el: ElementRef,
            private http: HttpClient,
        ) {}
    
        ngOnInit(): void {
            this.http.get(this.src, {responseType: 'text'}).subscribe(svg => {
                this.el.nativeElement.innerHTML = svg;
            });
        }
    }
    

    如果你不想将 app-svg 作为容器,你可以改用:

    this.el.nativeElement.outerHTML = svg;
    

    它会用他加载的 svg 替换 app-svg。希望这可以帮助其他试图完成同样事情的人。干杯!

    【讨论】:

    • 对这种方法要非常小心。从后端插入随机文本,如果没有检查其有效性的好方法是不是很安全。在没有任何保护的情况下直接操作 DOM 也会暴露一些风险。根据官方文档,您应该考虑使用 Renderer2 插入内容。
    猜你喜欢
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多