如何在Angular的innerHTML内容中显示FontAwesome图标?
问题背景
我用Angular 14开发项目,已经完成Font Awesome的集成,模板中用<fa-icon [icon]="faIconName">语法能正常显示图标。网站支持多语言,翻译内容存在JSON文件中,模板通过<section [innerHTML]="'key_1' | translate | safeHtml">加载带HTML的翻译内容(比如<b>、<br>标签),但直接在JSON里写<fa-icon>标签无法正常显示图标,请问该怎么解决?
相关代码示例:
语言JSON文件(assets\i18n)
"key_1":"<p><b>example text</b><br /><fa-icon [icon]=\"faPhoneSquare\"></fa-icon> +43 123 123 923</p>", "key_2":"<p><fa-icon [icon]=\"faPhoneSquare\"></fa-icon> +44 123 123 123</p>", "key_3":"<p><fa-icon [icon]=\"faPhoneSquare\"></fa-icon> +43 123 123 123</p>"
模板代码
<section> <h4 [translate]="'header_1'"></h4> <p> <fa-icon [icon]="faEnvelope" class="me-2"></fa-icon> Some static text with icon on left which displays fine </p> </section> <section [innerHTML]="'key_1' | translate | safeHtml"></section> <section [innerHTML]="'key_2' | translate | safeHtml"></section> <section [innerHTML]="'key_3' | translate | safeHtml"></section>
TypeScript代码
import { Component } from '@angular/core'; import { TranslationAppService } from '../../../common/services'; import { faPhoneSquare, faEnvelope } from '@fortawesome/free-solid-svg-icons'; @Component({ selector: 'app-contact', templateUrl: './contact.component.html', styleUrls: ['./contact.component.scss'] }) export class ContactComponent { faPhoneSquare = faPhoneSquare; faEnvelope = faEnvelope; }
核心原因
Angular不会编译通过[innerHTML]插入的Angular组件(比如<fa-icon>),组件的属性绑定[icon]也不会生效,只能识别普通HTML标签和样式。
解决方案
方法一:使用Font Awesome原生HTML/CSS图标(最简单)
直接用Font Awesome原生<i>标签+类名的方式,无需依赖Angular组件,就能在[innerHTML]中正常渲染:
确保Font Awesome CSS已引入
若之前只安装了@fortawesome/angular-fontawesome,需额外引入Font Awesome的CSS文件。通过npm安装@fortawesome/fontawesome-free后,在angular.json的styles数组中添加:"styles": [ "node_modules/@fortawesome/fontawesome-free/css/all.min.css", // 其他样式文件 ]修改JSON翻译文件
将<fa-icon>标签替换为原生<i>标签,使用对应Font Awesome类名:"key_1":"<p><b>示例文本</b><br /><i class='fa-solid fa-phone-square'></i> +43 123 123 923</p>", "key_2":"<p><i class='fa-solid fa-phone-square'></i> +44 123 123 123</p>", "key_3":"<p><i class='fa-solid fa-phone-square'></i> +43 123 123 123</p>"fa-solid代表图标样式(还有fa-regular、fa-brands等可选)fa-phone-square是具体图标类名
保留原有模板和TS代码
模板中的[innerHTML]和safeHtml管道无需修改,图标会直接渲染。若其他地方不需要faPhoneSquare变量,可从TS中移除。
方法二:自定义管道替换图标占位符(适合需用Angular组件的场景)
如果必须使用Angular Font Awesome组件(比如需要动态控制图标样式、绑定事件),可以在翻译文本中用占位符,再通过自定义管道替换为组件渲染后的内容:
修改JSON翻译文件,添加占位符
"key_1":"<p><b>示例文本</b><br />{{faPhoneSquare}} +43 123 123 923</p>"创建自定义管道
import { Pipe, PipeTransform } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { faPhoneSquare } from '@fortawesome/free-solid-svg-icons'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { ComponentFactoryResolver, Injector } from '@angular/core'; @Pipe({ name: 'replaceIcons' }) export class ReplaceIconsPipe implements PipeTransform { constructor( private sanitizer: DomSanitizer, private resolver: ComponentFactoryResolver, private injector: Injector ) {} transform(value: string): SafeHtml { // 创建fa-icon组件实例并生成HTML const factory = this.resolver.resolveComponentFactory(FaIconComponent); const componentRef = factory.create(this.injector); componentRef.instance.icon = faPhoneSquare; componentRef.changeDetectorRef.detectChanges(); const iconHtml = componentRef.location.nativeElement.outerHTML; componentRef.destroy(); // 替换占位符 const result = value.replace('{{faPhoneSquare}}', iconHtml); return this.sanitizer.bypassSecurityTrustHtml(result); } }修改模板,使用自定义管道
<section [innerHTML]="'key_1' | translate | replaceIcons"></section>注意:这种方式需要处理组件的创建和销毁,复杂度较高,仅在必要时使用。
内容的提问来源于stack exchange,提问作者Vereb

