问题
I am building an Angular application (Angular 4/5/6) and would like to use SVG sprites in my component template.
Question:
Assuming I already have my SVG icon sprite generated (icons.svg
), how can I get Angular to inject/import my SVG icon sprite into my component's template?
Is there a way to inject/import my SVG icon sprite into my component without having to use any 3rd party modules/directives and do it natively with Angular itself?
Background/Issue:
As discussed in this article, icons.svg
file would contain all the SVG icons defined as <symbol>
. Then I can render selected icons in my HTML using <use>
assuming the icons.svg
is injected in the DOM.
I generated SVG sprites using IcoMoon app, and saved the icons.svg
into my Angular application. Below is my sample Angular component (app.component.ts) in which I am trying to inject/import the icons.svg
file and trying to render the SVG icons in my HTML. However, Angular is not rending my SVG icons. I seems I am incorrectly injecting the SVG icon sprite file.
Updates:
- I am already aware of a similar question, SVG icon system with angular-cli, where the suggested answer was to use the Node module svg-sprite to generate a SVG sprites using the CSS mode. However, this is NOT what I am asking. I am NOT trying to generate the SVG sprites. I am trying get Angular components to be aware of my SVG sprite,
icons.svg
, and get it to render them in the HTML whenever I make use of them. - A solution was suggested,https://stackoverflow.com/a/50460361/4988010, to generate a CSS font from the SVG sprite. I feel this is NOT a feasible solution and instead is a "workaround" to not being able to use the SVG sprite.
app.component.ts: Live example on 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 {
}
回答1:
I think your root path is where you are having problems. In your code you are telling angular to look in app
but the browser sees this as https://your-site.com./icons
If you move your icon file under your /assets
folder, then it should be available already because the src\assets
folder is already included in angular.json
, the "assets"
collection tells Angular where to look.
<svg class="icon">
<use xlink:href="/assets/icons.svg#icon-rocket"></use> // Notice root path not "./"
</svg>
If you would like your files to be served from another directory all you need to do is add a path in your angular.json:
…
"assets": [
"src/favicon.ico",
"src/assets",
"src/your-dir"
],
…
Then in your code
<svg class="icon">
<use xlink:href="/your-dir/icons.svg#icon-rocket"></use>
</svg>
I wouldn't suggest adding /src/app
as an asset path, this would basically open up your entire app for serving files, making your entire directory accessible.
I forked your example and updated here
回答2:
you can convert your svg file to font by https://icomoon.io/app/#/select, upload your svg file and select it,click on the Generate Font then click the download button, download font file and choose font folder and put it in a folder in your project,
import font file into css files
@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;
}
declear your class like this
.icon-home:before {
content: "\ea77";
}
.icon-conection:before {
content: "\ea78";
}
.icon-rocket:before {
content: "\ea79";
}
and use it in your html
<p>Icon (rocket): <i class="icon-rocket"></i> </p>
The solution was to add the icons in the project, but if you want to use the svg code in the project, it's best to add the loader to it.
If you have used the webpack:
npm install svg-inline-loader --save-dev
Simply add configuration object to module.loaders like this.
{
test: /\.svg$/,
loader: 'svg-inline-loader'
}
more info
回答3:
I was in your same boat today with designers pushing back about the svg font. I also did not want to move the icon def out of the node_modules because it would change over time. I came up with a solution.
You need to first create an angular icon component, then do something like this:
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);
}
}
And then, in the 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>
I'm still working on scaling the solution as the width and height attributes don't work as expected. You can also expand on the inputs as I know I will.
Hope that helps.
回答4:
I solved this issue using angular material icon.
Angular material injects the SVG by id and without shadow-dom.
first install angular material:
"@angular/material": "^7.3.7", // change version according to your angular version
Import to your module:
MatIconModule
Then declare your SVG sprite in the app.component or service..
constructor(
private matIconRegistry: MatIconRegistry,
private domSanitizer: DomSanitizer) {
matIconRegistry.addSvgIconSet(this.domSanitizer.bypassSecurityTrustResourceUrl(`assets/sprite.svg`));
}
And last, In Html use angular material icon:
<mat-icon svgIcon="svg-id"></mat-icon> // or use as directive <div svgIcon="svg-id"></div>
Read more here
来源:https://stackoverflow.com/questions/50459291/how-to-inject-svg-icon-sprites-in-angular-component-html-dom