我正在为我的Angular项目开发一个自定义图标库,因为Font Awesome中的许多图标现在都不是免费的. 我使用Google Content Icons,将它们实现为样式表.然后我创建了一个图标服务和一个图标指令,以方便调用.

这是我的图标.service.ts:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class IconsService {
  constructor(private http: HttpClient, private sanitizer: DomSanitizer) {}

  getIcon(name: string): Observable<SafeHtml> {
    return this.http.get(`assets/icons/${name}.svg`, { responseType: 'text' }).pipe(
      map(svgString => this.sanitizer.bypassSecurityTrustHtml(svgString) as SafeHtml) // assert non-null
    );
  }
}

我的图标指令大多数工作在哪里完成:

import {Directive, ElementRef, Input, Renderer2} from '@angular/core';

@Directive({
  selector: '[icon]',
  standalone: true,
})
export class IconDirective {
  private _iconName: string = '';
  private _spin: boolean = false;
  private _size: string | undefined;
  private _flipHorizontal: boolean = false;
  private _flipVertical: boolean = false;
  private _color: string | undefined;

  @Input('icon')
  set icon(value: string) {
    const parts = value.split(' ');
    this._iconName = parts[0];

    this._spin = parts.includes('spin');

    this._flipHorizontal = parts.includes('flip-horizontal');

    this._flipVertical = parts.includes('flip-vertical');

    this._size = parts.find(part => part.match(/^[0-5]x$/)) || '1x'; // Default to 1x

    const colorPart = parts.find(part => part.startsWith('color-'));
    this._color = colorPart ? colorPart.split('-')[1] : undefined;

    this.updateIcon();
  }

  constructor(private el: ElementRef, private renderer: Renderer2) {
  }

  ngAfterViewInit(): void {
    this.setupLazyLoading();
  }

  private setupLazyLoading(): void {
    const options = {
      root: null, // observes changes in the viewport
      threshold: 0.01, // trigger when 1% of the element is visible
    };

    const observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          this.updateIcon();
          observer.unobserve(entry.target); // Stop observing once loaded
        }
      });
    }, options);

    observer.observe(this.el.nativeElement);
  }

  private updateIcon(): void {
    console.log('Updating icon');
    // Clear previous classes
    this.el.nativeElement.className = '';

    // Set text content to the icon name
    this.renderer.setProperty(this.el.nativeElement, 'textContent', this._iconName);
    this.renderer.addClass(this.el.nativeElement, 'material-icons');

    // Apply size, spin, and flip classes
    if (this._spin) {
      this.renderer.addClass(this.el.nativeElement, 'spin');
    }
    if (this._flipHorizontal) {
      this.renderer.addClass(this.el.nativeElement, 'flip-horizontal');
    }
    if (this._flipVertical) {
      this.renderer.addClass(this.el.nativeElement, 'flip-vertical');
    }
    if (this._size) {
      this.renderer.addClass(this.el.nativeElement, `icon-${this._size}`);
    }
    if (this._color) {
      this.renderer.setStyle(this.el.nativeElement, 'color', this._color);
    }
  }
}

此时我的html:

<h1>Icon examples</h1>
<h2>Sizing: <i icon="search"></i><i icon="search 2x"></i><i icon="search 3x"></i></h2>
<h2>Spinning: <i icon="search spin"></i></h2>
<h2>Flipping horizontally and vertically: <i icon="search flip-horizontal"></i><i icon="search flip-vertical"></i></h2>
<h2>Colors: <i icon="search color-blue"></i><i icon="search color-red"></i><i icon="search color-green"></i></h2>
<h1>Button example: <button><i icon="donut_large spin"></i>Loading</button></h1>
<button><i icon="settings 2x"></i></button>
<button><i icon="menu 2x"></i></button>
<!--<button><i icon="stacks 2x"></i></button>-->
<button><i icon="print 2x"></i></button>
<button><i icon="open_with 2x"></i></button>
<button><i icon="add 2x"></i></button>
<button><i icon="public 2x"></i></button>
<!--<button><i icon="captive_portal 2x"></i></button>-->
<button><i icon="filter_alt 2x"></i></button>
<button><i icon="filter_alt_off 2x"></i></button>
<button><i icon="arrow_forward_ios 2x"></i></button>
<button><i icon="arrow_back_ios 2x"></i></button>
<button><i icon="pan_tool 2x"></i></button>
<button><i icon="progress_activity 2x"></i></button>

但这是我在屏幕上看到的,一些图标(例如进度活动)没有渲染,我做错了什么?

last icon not visible/rendering

我try 更改浏览器,更改我的css以包括字体系列.没什么

 /*Icon base styles */
[icon] {
  display: inline-block;
  font-size: 16px;
  padding: 2px;
  fill-opacity: 0;
  vertical-align: middle;
  horiz-align: center;
}

 @font-face {
   font-family: 'Material Icons';
   font-style: normal;
   font-weight: 400;
   src: url(https://example.com/MaterialIcons-Regular.eot); /* For IE6-8 */
   src: local('Material Icons'),
   local('MaterialIcons-Regular'),
   url(https://example.com/MaterialIcons-Regular.woff2) format('woff2'),
   url(https://example.com/MaterialIcons-Regular.woff) format('woff'),
   url(https://example.com/MaterialIcons-Regular.ttf) format('truetype');
 }


/* Icon size variations */
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.spin {
  animation: spin 2s infinite linear;
  padding: 2px;
}

 .flip-horizontal {
   transform: scaleX(-1);
 }

 .flip-vertical {
   transform: scaleY(-1);
 }

 .flip-left {
   transform: rotateY(180deg);
 }

 .flip-right {
   transform: rotateY(-180deg);
 }

 .material-icons.icon-1x { font-size: 16px; } /* Default Material Icons size */
 .material-icons.icon-2x { font-size: 32px; }
 .material-icons.icon-3x { font-size: 48px; }
 .material-icons.icon-4x { font-size: 64px; }

推荐答案

我可以看到[progress_activity](https://fonts.google.com/icons?icon.query=progress_activity)Material Symbols集合中,但notMaterial Icons集合中.

我最初的猜测是,您按照说明安装了Material Icons,如果您想要像progress_activity这样的额外图标,那么您应该安装follow the directions for Material Symbols instead.

Angular相关问答推荐

RFDC.CommonJS或AMD依赖项可能会导致优化救助ANGURAL PROCEMENT with ngx-charts lib

添加@ nx/webpack插件 destruct 了Nativescript构建

Angular 服务错误处理响应类型=BLOB

ANGLE DI useFactory将参数传递给工厂函数

Angular 17-getEnvironment InjectorProviders出现异常

ANGLE v16独立组件不能与拦截器一起工作?

react 形式之间的循环关系

在以下位置升级到Angular 16 Break Sharepoint广告:This._history.replaceState不是函数

无法在单个元素上多次监听同一个事件

Angular 为什么延迟加载返回空路径?

如何从2个api获取数据并查看Angular material 表中的数据?

带有数据的 Angular 模板

Angular 无法从后端获取数据到前端

带有重定向的Angular 2 AuthGuard服务?

类型错误:无法读取未定义的属性

移除 Angular 组件创建的宿主 HTML 元素 Select 器

Angular将 Select 值转换为 int

Angular 应用程序中的语法错误:Unexpected token <

Angular 2表单验证重复密码

如何从指令访问主机组件?