Как внедрить спрайты значков SVG в HTML DOM компонента Angular?

Я создаю приложение Angular (Angular 4/5/6) и хотел бы использовать спрайты SVG в моем шаблоне компонента.

Вопрос: Предполагая, что у меня уже есть сгенерированный спрайт значка SVG (icons.svg), как я могу заставить Angular вставлять / импортировать мой спрайт значка SVG в шаблон моего компонента?

Есть ли способ внедрить / импортировать мой спрайт значка SVG в мой компонент без использования каких-либо сторонних модулей / директив и сделать это изначально с помощью самого Angular?

Справочная информация / проблема:

Как обсуждалось в эта статья, файл icons.svg будет содержать все значки SVG, определенные как <symbol>. Затем я могу отобразить выбранные значки в моем HTML с помощью <use>, предполагая, что icons.svg внедрен в DOM.

Я сгенерировал SVG-спрайты с помощью Приложение IcoMoon и сохранил icons.svg в моем приложении Angular. Ниже приведен мой образец компонента Angular (app.component.ts), в котором я пытаюсь внедрить / импортировать файл icons.svg и отобразить значки SVG в моем HTML. Однако Angular не разрывает мои значки SVG. Кажется, я неправильно вставляю файл спрайта значков SVG.

Обновления:

  1. Мне уже известен аналогичный вопрос, Система значков SVG с angular -cli, где предложенным ответом было использование модуля узла svg-спрайт для генерации спрайтов SVG с использованием режима CSS. Однако я спрашиваю НЕ об этом. Я НЕ пытаюсь создавать спрайты SVG. Я пытаюсь заставить компоненты Angular знать о моем спрайте SVG, icons.svg, и заставить его отображать их в HTML всякий раз, когда я их использую.
  2. Было предложено решение https://stackoverflow.com/a/50460361/4988010 для создания шрифта CSS из спрайта SVG. Я считаю, что это НЕ осуществимое решение, а вместо этого «обходной путь» невозможности использовать спрайт SVG.

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 {
}

Создайте компонент my-icon, который принимает ссылку на вашу таблицу спрайтов для @input. Проверь это ... Stackblitz

wrob 16.01.2019 03:01
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
8
1
11 370
4

Ответы 4

вы можете преобразовать свой файл svg в шрифт с помощью https://icomoon.io/app/#/select, загрузить свой файл svg и выбрать его, щелкнуть «Создать шрифт», затем нажать кнопку загрузки, загрузите файл шрифта, выберите папку шрифтов и поместите его в папку в своем проекте,

импортировать файл шрифта в файлы 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.loaders следующим образом.

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

больше информации

Приятно знать, что я могу конвертировать свои SVG-спрайты в шрифты, однако я не думаю, что это реальное решение. Почему я не могу напрямую использовать сами спрайты SVG? Почему я должен обойти главную проблему?

Zythyr 22.05.2018 08:07

У меня уже была эта проблема, и мне пришлось использовать это решение, этот метод решает вашу проблему. Если у вас нет другой причины использовать svg в Angular

Alireza Varmaghani 22.05.2018 09:04

Если вы используете WebPack, вы можете решить свою проблему, добавив загрузчик, я добавляю объяснение в тексте выше. я надеюсь, что это поможет тебе

Alireza Varmaghani 22.05.2018 09:27

Я не понимаю, почему мы должны использовать обходной путь «CSS / Font» вместо возможности напрямую использовать SVG. Это ошибка в Angular? Разве Angular недостаточно гибкости для поддержки основных функций, таких как возможность загрузки внешних файлов?

Zythyr 22.05.2018 19:51

@AlirezaVarmaghani при создании производственной сборки напрямую добавляет файл в его корень (svgs и шрифты). Он должен напрямую импортироваться в сам CSS.

Abhishek 26.07.2018 08:28

Я думаю, что ваш корневой путь - это то место, где у вас возникают проблемы. В вашем коде вы указываете angular искать в app, но браузер видит это как https://your-site.com./icons.

Если вы переместите файл значка в папку /assets, он уже должен быть доступен, потому что папка src\assets уже включена в angular.json, коллекция "assets" сообщает Angular, где искать.

<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 в качестве пути к ресурсам, это в основном открыло бы все ваше приложение для обслуживания файлов, сделав доступным весь ваш каталог.

Раздвоил твой пример и обновил здесь

Если я использую значки из спрайта SVG на нескольких экранах, тогда это будет отдельный сетевой вызов для спрайта для визуализации отдельного значка, не так ли? Есть ли способ ограничить этот вызов до одного раза при загрузке приложения?

parthsw 05.08.2019 15:26

@parthsw Если вы хотите загрузить все спрайты при загрузке, я бы сохранил все спрайты в одном файле эта статья объясняет это довольно хорошо, короче говоря, вы добавляете все спрайты как символы в один файл svg, а затем используйте его как <svg><use xlink:href = "assets/svgSprites.svg#spriteID"></use></svg>

Andy Braham 06.08.2019 13:06

Сегодня я был в той же лодке, когда дизайнеры возражали против шрифта svg. Я также не хотел перемещать значок def из node_modules, потому что со временем он будет меняться. Я придумал решение.

Вам нужно сначала создать компонент значка angular, а затем сделать что-то вроде этого:

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>

Я все еще работаю над масштабированием решения, поскольку атрибуты ширины и высоты работают не так, как ожидалось. Вы также можете расширить входные данные, насколько я знаю.

Надеюсь, это поможет.

Я решил эту проблему, используя угловой значок материала.

Угловой материал вводит SVG по идентификатору и без теневой дом.

Сначала установите угловой материал:

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

Импортируйте в свой модуль:

MatIconModule

Затем объявите свой 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>

Подробнее читайте здесь

Другие вопросы по теме