Angular 2如何从innerHTML执行脚本标记

haa*_*i47 5 javascript http angular

我已经HTML通过http.get()方法加载页面,并且我将此页面的内容添加到div标签.

getRequestToAssignPage (param: string) : any {

    return this.$http.get(param)
        .map((res: Response) => {

            this.status = res;

            return res.text();
        })
        .toPromise()
        .then(response => {



            let restr: string = response;



            restr = restr.replace(/(<head[^>]*)(?:[^])*?\/head>/ig, '')
                .replace(/(<(\/?)body([^>]*?)>)/g, '')
                .replace(/(<style[^>]*)(?:[^])*?\/style>/g, '')
                .replace(/(<(\/?)html([^>]*?)>)/g, '')
                .replace(/(<app-root[^>]*)(?:[^])*?\/app-root>/ig, '')
                .replace(/(<\?[\s\S]*?\?>)|(<!DOCTYPE\s+\w+\s+\[[\s\S]*?\]>)|(<!\w[\s\S]*?>)/g, '')
                .replace(/(href\s*=\s*(?:"))/ig, 'href="/#')
                .replace(/(href\s*=\s*(?:'))/ig, "href='/#");



            this.response = restr;


        })
        .catch(error => this.status = error );

}
Run Code Online (Sandbox Code Playgroud)

你怎么看,这个方法,把响应放在变量中,并用正则表达式解析字符串确定,然后我把它添加到div,就像这样

<div [innerHTML]="response | safe"></div>
Run Code Online (Sandbox Code Playgroud)

好,我的页面显示.但是,脚本不起作用.它们存在于div标签中,但不执行.

我曾尝试过这样做,eval()但结果很糟糕

let scripts: string[] = restr.match(/\<scr[\s\S]*?ipt>/g);

            this.srcfield.nativeElement.innerHTML = '';

            scripts.forEach((value, index) => {
                eval.call(null, (this.srcfield.nativeElement.innerHTML = value));
            });
Run Code Online (Sandbox Code Playgroud)

SyntaxError:意外的令牌<

为什么innerHTML不执行加载的脚本标记?我怎么能解决这个问题?

Pav*_*ykh 11

基于Adam的解决方案,您可以实现自定义指令以及管道并将脚本重新插入DOM.这将解释两种情况:内联脚本和"src"脚本.请记住,允许这样的脚本非常危险.

管:

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({ name: 'safeHtml' })
export class SafeHtmlPipe implements PipeTransform {
    constructor(private sanitizer: DomSanitizer) { }

    transform(html) {
        return this.sanitizer.bypassSecurityTrustHtml(html);
    }
}
Run Code Online (Sandbox Code Playgroud)

指示:

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

@Directive({ selector: '[runScripts]' })
export class RunScriptsDirective implements OnInit {
    constructor(private elementRef: ElementRef) { }
    ngOnInit(): void {
        setTimeout(() => { // wait for DOM rendering
            this.reinsertScripts();
        });
    }
    reinsertScripts(): void {
        const scripts = <HTMLScriptElement[]>this.elementRef.nativeElement.getElementsByTagName('script');
        const scriptsInitialLength = scripts.length;
        for (let i = 0; i < scriptsInitialLength; i++) {
            const script = scripts[i];
            const scriptCopy = <HTMLScriptElement>document.createElement('script');
            scriptCopy.type = script.type ? script.type : 'text/javascript';
            if (script.innerHTML) {
                scriptCopy.innerHTML = script.innerHTML;
            } else if (script.src) {
                scriptCopy.src = script.src;
            }
            scriptCopy.async = false;
            script.parentNode.replaceChild(scriptCopy, script);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

<div [innerHTML]="myDynamicMarkup | safeHtml" runScripts></div>
Run Code Online (Sandbox Code Playgroud)

  • @WalterLuszczyk我知道你的问题很久以前就被问过,但如果其他人也有同样的问题,我会提供两个建议。首先,您始终可以调整“setTimeout()”中的毫秒数。但更好的解决方案是在元素上放置 *ngIf,这样它仅在数据存在时才呈现。这应该强制指令在数据加载后运行。 (2认同)

ada*_*ort 5

在您的模板中,您可以设置以下内容:

<div #htmlContainer [innerHTML]="trustedHTML"></div>
Run Code Online (Sandbox Code Playgroud)

在相应的组件中,您可以将HTML加载到模板中,构建一个脚本标记数组,eval每个标记标记:

@ViewChild('htmlContainer') container;

ngOnInit() {
  this.http.get('html-file.html').subscribe((res: Response) => {
    this.trustedHTML = this.sanitizer.bypassSecurityTrustHtml(res.text());

    setTimeout(() => { //wait for DOM rendering
      let scripts = this.container.nativeElement.getElementsByTagName('script');
      for (let script of scripts){
        eval(script.text)
      }
    })

  });
Run Code Online (Sandbox Code Playgroud)

我讨厌我不得不求助于使用setTimeouteval看似简单的东西,但它有效.

......但不是<script src="....我最终导入了jQuery并使用了$(parent).load(url);.如果有人有纯粹的Angular解决方案,请发布.