如何在Angular组件HTML DOM中注入SVG图标精灵?

时间:2018-05-22 03:21:18

标签: angular svg angular-components svg-sprite

我正在构建一个Angular应用程序(Angular 4/5/6),并希望在我的组件模板中使用SVG sprite。

问题: 假设我已经生成了我的SVG图标精灵(icons.svg),我如何让Angular将我的SVG图标精灵注入/导入我的组件模板?

有没有办法将我的SVG图标精灵注入/导入我的组件而不必使用任何第三方模块/指令,并使用Angular本身进行本地操作?

背景/问题:

this article中所述,icons.svg文件将包含定义为<symbol>的所有SVG图标。然后我可以使用<use>在我的HTML中呈现选定的图标,假设在{DOM}中注入了icons.svg

我使用IcoMoon app生成了SVG精灵,并将icons.svg保存到我的Angular应用程序中。下面是我的示例Angular组件( app.component.ts ),其中我试图注入/导入icons.svg文件并尝试在我的HTML中呈现SVG图标。但是,Angular并没有依赖我的SVG图标。我似乎错误地注入了SVG图标精灵文件。

更新:

  1. 我已经知道一个类似的问题,SVG icon system with angular-cli,其中建议的答案是使用Node模块 svg-sprite 使用CSS模式生成SVG精灵。但是,这不是我要问的。我不是想生成SVG精灵。我正在尝试让Angular组件知道我的SVG精灵icons.svg,并在我使用它时让它在HTML中呈现它们。
  2. 建议使用https://stackoverflow.com/a/50460361/4988010解决方案,从SVG精灵生成CSS字体。我觉得这不是一个可行的解决方案,而是一个无法使用SVG精灵的“解决方法”。
  3. app.component.ts :StackBlitz上的实例:https://stackblitz.com/edit/angular-bbr2kh?file=src/app/app.component.ts

    import { Component } from '@angular/core';
    // import `./icons.svg`; // This import method doesn't work
    
    
    @Component({
      selector: 'my-app',
      template: `
    
       <!-- This import method doesn't work -->
       <!-- <script src="./icons.svg"></script>  -->
    
      <p>
      Hello this is a sample Angular 6 component.
      </p>
    
      <p>Testing to see if SVG icon sprite import works. See below if icons appear. </p>
      <p>Icon (home): <svg class="icon icon-home"><use xlink:href="#icon-home"></use></svg> </p>
      <p>Icon (rocket): <svg class="icon icon-rocket"><use xlink:href="#icon-rocket"></use></svg> </p>
      <p>Icon (wifi): <svg class="icon icon-connection"><use xlink:href="#icon-connection"></use></svg>
    
      <!-- This import method doesn't work -->
      <!-- <p>Icon (home): <svg class="icon icon-home"><use xlink:href="./icons.svg#icon-home"></use></svg> </p>-->
    
       </p>
      `,
      styles: [`
    
      .icon {
      display: inline-block;
      width: 1em;
      height: 1em;
      stroke-width: 0;
      stroke: currentColor;
      fill: currentColor;
      }
    
      `]
    })
    export class AppComponent {
    }
    

4 个答案:

答案 0 :(得分:2)

我认为您的根源就是您遇到问题的地方。在您的代码中,您告诉angular在app中查找,但浏览器将其视为https://your-site.com./icons

如果将图标文件移动到/assets文件夹下,则src\assets集合将告诉您angular.json文件夹中已经包含"assets"文件夹,因此该图标文件应该已经可用角度看哪里。

<svg class="icon">
   <use xlink:href="/assets/icons.svg#icon-rocket"></use> // Notice root path not "./"
</svg>

如果您希望从另一个目录提供文件,您要做的就是在angular.json中添加一个路径:

…
"assets": [
   "src/favicon.ico",
   "src/assets",
   "src/your-dir"
],
…

然后在您的代码中

<svg class="icon">
   <use xlink:href="/your-dir/icons.svg#icon-rocket"></use>
</svg>

我不建议添加/src/app作为资产路径,这基本上可以打开整个应用程序来提供文件,从而使整个目录都可以访问。

我分叉了您的示例,并更新了here

答案 1 :(得分:0)

今天我和您在同一条船上,设计师们回头介绍了svg字体。我也不想将图标def从node_modules中移出,因为它会随着时间变化。我想出了一个解决方案。

您需要首先创建一个有角度的图标组件,然后执行以下操作:

import { Component, OnInit, Input } from '@angular/core';
declare const require;
@Component({
  selector: 'my-icon',
  templateUrl: './my-icon.component.html',
  styleUrls: ['./my-icon.component.scss']
})
export class IconComponent implements OnInit {

  constructor() { }

  @Input() icon: string = "";
  @Input() x: string = "0";
  @Input() y: string = "0";
  @Input() fillColor: string = "black";
  @Input() strokeColor: string = "black";
  @Input() height: string = "";
  @Input() width: string = "";
  private baseUrl: string = require("../../../../../node_modules/path/to/defs.svg") + "#beginning-of-iconset-";

  svgUrl: string = "";

  ngOnInit() {
  }

  ngAfterViewInit() {
    setTimeout(()=>{
      this.svgUrl = this.baseUrl + this.icon;
    },0);

  }

}

然后在html中:

<svg [attr.height]="height" [attr.width]="width" xmlns="http://www.w3.org/2000/svg">
  <use [attr.href]="svgUrl" [attr.x]="x" [attr.y]="y" [attr.fill]="fillColor" [attr.stroke]="strokeColor" />
</svg>

由于width和height属性无法按预期工作,我仍在扩展解决方案。我也知道,您也可以扩展输入。

希望有帮助。

答案 2 :(得分:0)

我使用角形材质图标解决了这个问题。

角度材料按id注入SVG,并且没有 shadow-dom

首先安装角材:

"@angular/material": "^7.3.7", // change version according to your angular version 

导入您的模块:

MatIconModule

然后在app.component或服务中声明您的SVG精灵。

    constructor(
        private matIconRegistry: MatIconRegistry,
        private domSanitizer: DomSanitizer) { 
matIconRegistry.addSvgIconSet(this.domSanitizer.bypassSecurityTrustResourceUrl(`assets/sprite.svg`));
        }

最后,在HTML中使用角度材质图标:

<mat-icon svgIcon="svg-id"></mat-icon> // or use as directive <div svgIcon="svg-id"></div>

Read more here

答案 3 :(得分:-1)

您可以将您的svg文件转换为https://icomoon.io/app/#/select字体,上传您的svg文件并选择它,单击Generate Font然后单击下载按钮, 下载字体文件并选择字体文件夹并将其放在项目的文件夹中, enter image description here

将字体文件导入css文件

@font-face {
   font-family: 'icomoon';
   src:  url('fonts/icomoon.eot?31svmk');
   src:  url('fonts/icomoon.eot?31svmk#iefix') format('embedded-opentype'),
   url('fonts/icomoon.ttf?31svmk') format('truetype'),
   url('fonts/icomoon.woff?31svmk') format('woff'),
   url('fonts/icomoon.svg?31svmk#icomoon') format('svg');
  font-weight: normal;
  font-style: normal;
}

像你这样谴责你的班级

.icon-home:before {
  content: "\ea77";
}
.icon-conection:before {
  content: "\ea78";
}
.icon-rocket:before {
 content: "\ea79";
}

并在你的html中使用它

  <p>Icon (rocket): <i class="icon-rocket"></i> </p>

解决方案是在项目中添加图标,但如果要在项目中使用svg代码,最好将加载器添加到项目中。

如果您使用过网络包:

  npm install svg-inline-loader --save-dev

只需将配置对象添加到module.loader就可以了。

{
    test: /\.svg$/,
    loader: 'svg-inline-loader'
}

more info