Angular服务配置中HTML链接无法渲染,如何解决?
Angular中SafeHtml变量无法渲染为可点击链接的解决方法
问题场景
在Angular项目里,我在xxxxxConfig服务中定义了SafeHtml类型的xxxVaultLink变量,赋值为HTML链接代码,然后把它插入到whatHappensNextItemsForEmailxxx数组的第三个元素中。但组件调用该数组后,页面没渲染出可点击链接,反而直接显示完整的HTML标签文本。
服务代码
import { Injectable } from "@angular/core"; import { SafeHtml } from "@angular/platform-browser"; @Injectable() export class xxxxxConfig { xxxVaultLink: SafeHtml; whatHappensNextItemsForEmailxxx: string[]; whatHappensNextItemsForEmailSubTextxxx: string[]; constructor() { this.xxxVaultLink = `<a href="https://www.w3schools.com" target="_blank">xxx xx</a>`; this.whatHappensNextItemsForEmailxxx = [ `Confirmation of payment and a copy of your receipt has been emailed to you. You should receive it shortly.`, `xxxx will send your xxxxxdocuments (xxxxx) by post within 5 days.`, `A copy of your renewal xxxxx along with any supporting docs can be found in your ${this.xxxVaultLink} within the next 2 - 3 days.`, ]; this.whatHappensNextItemsForEmailSubTextxxx = [ `(If you wish to receive your receipt by post, please contact us on 08xxxxx)`, `Important: please ensure that you keep your documents safe as they form the basis of your xxxx with xxx.`, ``, ]; }
组件代码
whatHappensNext() { if (!this.isxxxxy) { this.whatHappensNextItems = this.isxxxxPhoneNumber ? this.xxxxConfig.whatHappensNextItemsForEmailxxx : this.xxxxConfig.whatHappensNextItemsForPost; this.whatHappensNextItemsSubText = this.isxxxxPhoneNumber ? this.xxxxConfig.whatHappensNextItemsForEmailSubTextxxx : this.xxxxConfig.whatHappensNextItemsForPostSubText; } }
核心原因
用模板字符串拼接SafeHtml变量和普通字符串时,SafeHtml会被强制转成普通字符串,丢失了Angular赋予的安全标记,导致Angular把整个内容当成纯文本,不会解析HTML标签。
解决方法
方法一:将数组改为SafeHtml类型,用DomSanitizer拼接内容
- 修改服务代码,注入
DomSanitizer,把数组类型改成SafeHtml[],并安全拼接内容:
import { Injectable } from "@angular/core"; import { SafeHtml, DomSanitizer } from "@angular/platform-browser"; @Injectable() export class xxxxxConfig { xxxVaultLink: SafeHtml; whatHappensNextItemsForEmailxxx: SafeHtml[]; whatHappensNextItemsForEmailSubTextxxx: string[]; constructor(private sanitizer: DomSanitizer) { // 用sanitizer标记链接为安全HTML this.xxxVaultLink = this.sanitizer.bypassSecurityTrustHtml( `<a href="https://www.w3schools.com" target="_blank">xxx xx</a>` ); // 把每个数组元素都转成SafeHtml类型 this.whatHappensNextItemsForEmailxxx = [ this.sanitizer.bypassSecurityTrustHtml( `Confirmation of payment and a copy of your receipt has been emailed to you. You should receive it shortly.` ), this.sanitizer.bypassSecurityTrustHtml( `xxxx will send your xxxxxdocuments (xxxxx) by post within 5 days.` ), this.sanitizer.bypassSecurityTrustHtml( `A copy of your renewal xxxxx along with any supporting docs can be found in your ${this.xxxVaultLink} within the next 2 - 3 days.` ), ]; this.whatHappensNextItemsForEmailSubTextxxx = [ `(If you wish to receive your receipt by post, please contact us on 08xxxxx)`, `Important: please ensure that you keep your documents safe as they form the basis of your xxxx with xxx.`, ``, ]; } }
- 组件中同步修改变量类型:
// 组件内定义变量时指定类型 whatHappensNextItems: SafeHtml[]; whatHappensNextItemsSubText: string[]; whatHappensNext() { if (!this.isxxxxy) { this.whatHappensNextItems = this.isxxxxPhoneNumber ? this.xxxxConfig.whatHappensNextItemsForEmailxxx : this.xxxxConfig.whatHappensNextItemsForPost; this.whatHappensNextItemsSubText = this.isxxxxPhoneNumber ? this.xxxxConfig.whatHappensNextItemsForEmailSubTextxxx : this.xxxxConfig.whatHappensNextItemsForPostSubText; } }
- 模板中用
[innerHTML]绑定渲染:
<div *ngFor="let item of whatHappensNextItems; let i = index"> <p [innerHTML]="item"></p> <p>{{ whatHappensNextItemsSubText[i] }}</p> </div>
方法二:拆分内容,模板中单独插入链接
如果不想改数组类型,可以把带链接的文本拆成普通文本和链接两部分,在模板里分别渲染:
- 修改服务,新增链接数组:
import { Injectable } from "@angular/core"; import { SafeHtml, DomSanitizer } from "@angular/platform-browser"; @Injectable() export class xxxxxConfig { xxxVaultLink: SafeHtml; whatHappensNextItemsForEmailxxx: string[]; whatHappensNextLinksForEmailxxx: (SafeHtml | null)[]; whatHappensNextItemsForEmailSubTextxxx: string[]; constructor(private sanitizer: DomSanitizer) { this.xxxVaultLink = this.sanitizer.bypassSecurityTrustHtml( `<a href="https://www.w3schools.com" target="_blank">xxx xx</a>` ); // 文本中用{{link}}标记链接位置 this.whatHappensNextItemsForEmailxxx = [ `Confirmation of payment and a copy of your receipt has been emailed to you. You should receive it shortly.`, `xxxx will send your xxxxxdocuments (xxxxx) by post within 5 days.`, `A copy of your renewal xxxxx along with any supporting docs can be found in your {{link}} within the next 2 - 3 days.`, ]; // 对应位置存放链接,没有链接的位置设为null this.whatHappensNextLinksForEmailxxx = [null, null, this.xxxVaultLink]; this.whatHappensNextItemsForEmailSubTextxxx = [ `(If you wish to receive your receipt by post, please contact us on 08xxxxx)`, `Important: please ensure that you keep your documents safe as they form the basis of your xxxx with xxx.`, ``, ]; } }
- 组件中同时获取文本和链接数组:
whatHappensNextItems: string[]; whatHappensNextLinks: (SafeHtml | null)[]; whatHappensNextItemsSubText: string[]; whatHappensNext() { if (!this.isxxxxy) { if (this.isxxxxPhoneNumber) { this.whatHappensNextItems = this.xxxxConfig.whatHappensNextItemsForEmailxxx; this.whatHappensNextLinks = this.xxxxConfig.whatHappensNextLinksForEmailxxx; this.whatHappensNextItemsSubText = this.xxxxConfig.whatHappensNextItemsForEmailSubTextxxx; } else { this.whatHappensNextItems = this.xxxxConfig.whatHappensNextItemsForPost; // 为post场景生成对应长度的空链接数组 this.whatHappensNextLinks = new Array(this.whatHappensNextItems.length).fill(null); this.whatHappensNextItemsSubText = this.xxxxConfig.whatHappensNextItemsForPostSubText; } } }
- 模板中拆分渲染:
<div *ngFor="let item of whatHappensNextItems; let i = index"> <p> {{ item.split('{{link}}')[0] }} <span *ngIf="whatHappensNextLinks[i]" [innerHTML]="whatHappensNextLinks[i]"></span> {{ item.split('{{link}}')[1] || '' }} </p> <p>{{ whatHappensNextItemsSubText[i] }}</p> </div>
注意事项
- 不要直接拼接HTML字符串后用
innerHTML渲染,必须通过DomSanitizer标记为安全HTML,防止XSS攻击。 SafeHtml类型只有通过[innerHTML]绑定才会被解析成HTML,普通的{{}}插值会把内容当成纯文本显示。
内容的提问来源于stack exchange,提问作者tercou1
相关产品推荐
相关产品推荐

