可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have load the HTML
page by http.get()
method, and i add content this page to div tag.
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 ); }
How you do you see, this method, put response in variable, and parse string by regular expressions Ok, and next I add it to div, like this
<div [innerHTML]="response | safe"></div>
Good, my page is display. But, scripts doesn't work. They are exist in the div tag, but doesn't execute.
I had tried do that with eval()
but this finished by poorly
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)); });
SyntaxError: Unexpected token <
Why innerHTML
doesn't execute loaded script tags? How i can fix that?
回答1:
Based on the Adam's solution you can implement a custom directive along with the pipe and re-insert scripts into the DOM. This would account for both cases: inline scripts and "src" scripts. Keep in mind that allowing scripts like so is very dangerous.
Pipe:
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); } }
Directive:
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); } } }
Usage:
<div [innerHTML]="myDynamicMarkup | safeHtml" runScripts></div>
回答2:
In your template, you can set up something like:
<div #htmlContainer [innerHTML]="trustedHTML"></div>
In the corresponding component, you can load your HTML into your template, build up an array of script tags, and eval
each one:
@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) } }) });
I hate that I have to resort to using setTimeout
and eval
for something so seemingly simple, but it works.
...but not for <script src="...
. I ended up importing jQuery and using $(parent).load(url);
. If someone has a pure Angular solution, please post it.