首页 > 解决方案 > Angular 7:div innerHTML 绑定在有或没有对位置 html 数据进行 html 清理的情况下都不起作用

问题描述

我的数据源来自 REST 端点,它是一个 html 内容。获得数据后,我尝试将其放入 innerHTML 中, <div [innerHTML]="mydata"></div>但它不起作用。为了确保mydata有数据,我尝试mydata使用插值打印{{mydata}},它工作正常。然后我四处搜索,发现mydata需要对其进行清理,因为出于安全考虑,Angular 不允许这样做。因此,我创建了一个管道,在其中使用它对其进行了消毒, this.sanitizer.bypassSecurityTrustHtml(mydata)但即使在此之后它也无法正常工作。

注意:我确实用简单的 HTML 内容尝试了相同的代码,它运行良好。mydata在有问题的情况下有位置数据。

消毒代码:

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, 
SafeResourceUrl } from '@angular/platform-browser';

@Pipe({
   name: 'safe'
})
export class SafePipe implements PipeTransform {

constructor(protected sanitizer: DomSanitizer) {}

public transform(value: any, type: string): SafeHtml | SafeStyle | 
    SafeScript | SafeUrl | SafeResourceUrl {
    switch (type) {
        case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);              
        case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);
        case 'script': return this.sanitizer.bypassSecurityTrustScript(value);
        case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);
        case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);
        default: throw new Error(`Invalid safe type specified: ${type}`);
    }

然后我打电话给: <div [innerHTML]="mydata | safe :'html'"></div>

根据@James Essex 的回答,我将代码修改为:

location.service.ts:从“rxjs”导入 { Observable }

 getData(): Observable <any> {
    return this.http.get(sourceUrl, { responseType: 'text'}).pipe(
      tap(value =>  {
        console.log(value);
     })
    );  
  }

component.ts `responseDataFromObservable: any; ngOnInit(){ this.callLocationData();

 callLocationData() {
this.locationService.getData().subscribe(response => {
  response = this.responseDataFromObservable;
     })
   }
 }

而 html 是:正是@James Essex 所说的。

但仍然没有运气,UI 显示空白屏幕,没有任何错误。

标签: angular

解决方案


我认为您不应该尝试绕过安全性或将原始 HTML 注入<div [innerHTML]="myData">. 这似乎直接违反了跨视域脚本的Angular 安全文档。

模板层使用 shadow DOM 不直接接触 HTML,并且可以通过Renderer2.

我建议开发一个指令,而不是使用Renderer2ElementRef

例子:

角度指令:
import { Directive, Renderer2, ElementRef, OnInit, Input } from '@angular/core';

@Directive({
  selector: '[appSafeData]'
})
export class SafeDataDirective implements OnInit {
  @Input passedHtmlData;

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

  ngOnInit() {
    this.renderer.appendChild(this.el.nativeElement, passedHtmlData);
  }
}
对应服务:
  getData(): Observable<any> {
    this.http.get('putUrlHere');
  }
对应组件:
  let responseDataFromObservable; // Put whatever type it is string, interfaced typings or any?

  ngOnInit() {
    callLocationData();
  }

  callLocationData() {
    this.locationService.getData().subscribe(response => {
      response = this.responseDataFromObservable;
    }
  }
对应的HTML:
<ng-container *ngIf="responseDataFromObservable">
  <div appSafeData [passedHtmlData]="responseDataFromObservable" id="my-data-wrapper">
    <!-- Your API data as HTML will be added here -->
  </div>
</ng-container>

注意:我确信使用设置模板可能会更好,<ng-container>但这样的方法是在不影响安全性的情况下注入数据的更好方法。

可能有帮助的其他链接:

  1. Alligator.io - 使用 Renderer2
  2. Alligator.io - 使用 ng-container
  3. Angular.io - Renderer2 文档

推荐阅读