我正在编写Angular应用程序,并且要显示HTML响应。
我怎么做?如果我仅使用绑定语法,{{myVal}}
那么它将编码所有HTML字符(当然)。
我需要以某种方式结合innerHTML
的div
对变量的值。
我正在编写Angular应用程序,并且要显示HTML响应。
我怎么做?如果我仅使用绑定语法,{{myVal}}
那么它将编码所有HTML字符(当然)。
我需要以某种方式结合innerHTML
的div
对变量的值。
Answers:
Angular 2.0.0和Angular 4.0.0 final
为了安全起见
<div [innerHTML]="myVal"></div>
DOM Sanitizer
需要使用Angulars DOM清理器将潜在的不安全HTML明确标记为受信任,因此不会剥离内容的潜在不安全部分
<div [innerHTML]="myVal | safeHtml"></div>
用类似的管道
@Pipe({name: 'safeHtml'})
export class Safe {
constructor(private sanitizer:DomSanitizer){}
transform(style) {
return this.sanitizer.bypassSecurityTrustHtml(style);
//return this.sanitizer.bypassSecurityTrustStyle(style);
// return this.sanitizer.bypassSecurityTrustXxx(style); - see docs
}
}
和文档:https : //angular.io/api/platform-browser/DomSanitizer
安全警告
信任用户添加的HTML可能会带来安全风险。前面提到的文档状态:
调用任何
bypassSecurityTrust...
API都会禁用Angular对传入值的内置清理功能。仔细检查和审核进入此调用的所有值和代码路径。确保为此安全上下文适当地转义了所有用户数据。有关更多详细信息,请参见《安全指南》。
角度标记
就像是
class FooComponent {
bar = 'bar';
foo = `<div>{{bar}}</div>
<my-comp></my-comp>
<input [(ngModel)]="bar">`;
与
<div [innerHTML]="foo"></div>
不会导致Angular在中处理任何特定于Angular的东西foo
。Angular在生成时用生成的代码替换了Angular特定的标记。Angular不会处理在运行时添加的标记。
要添加包含Angular特定标记(属性或值绑定,组件,指令,管道等)的HTML,需要在运行时添加动态模块并编译组件。此答案提供了更多详细信息。如何使用/创建动态模板以使用Angular 2.0编译动态组件?
import { BrowserModule, DomSanitizer } from '@angular/platform-browser'
import { Pipe } from '@angular/core'
[innerHtml]
在大多数情况下是个不错的选择,但是如果字符串太大或在html中需要硬编码样式时,它会失败。
我想分享其他方法:
您需要做的就是在html文件中创建一个div并为其指定一些ID:
<div #dataContainer></div>
然后,在Angular 2组件中,创建对此对象的引用(此处为TypeScript):
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
templateUrl: "some html file"
})
export class MainPageComponent {
@ViewChild('dataContainer') dataContainer: ElementRef;
loadData(data) {
this.dataContainer.nativeElement.innerHTML = data;
}
}
然后只需使用loadData
函数将一些文本附加到html元素即可。
这只是使用本机javascript的一种方式,但是在Angular环境中。我不建议这样做,因为它会使代码更混乱,但有时没有其他选择。
nativeElement
直接访问的属性(这被认为是不好的做法)外,我与其他解决方案没有什么不同。我敢肯定[innerHTML]="..."
,在Angular2的实践中也做了相同的事情。
[innerHTML]
在Angular2中遇到大型字符串的问题吗?
[innerHtml]
删除HTML中硬编码的样式。为了集成所见即所得的编辑器,我不得不使用这里列出的方法。
[innerHTML]
方法却没有。
在angular2@2.0.0-alpha.44上:
使用时,HTML绑定将不起作用{{interpolation}}
,请改用“表达式”:
无效
<p [innerHTML]="{{item.anleser}}"></p>
->引发错误(插值而不是期望的表达式)
正确
<p [innerHTML]="item.anleser"></p>
->这是正确的方法。
您可以在表达式中添加其他元素,例如:
<p [innerHTML]="'<b>'+item.anleser+'</b>'"></p>
暗示
使用[innerHTML]
(或通过其他类似element.appenChild()
或类似方式动态添加)添加的HTML 不会被Angular处理,除非出于安全目的进行了清理。
仅当将HTML静态添加到组件模板时,此类操作才起作用。如果需要,可以在运行时创建组件,如我如何使用/创建动态模板以使用Angular 2.0编译动态组件中所述。
如果其中包含用户创建的内容,则不选择不使用Angular的DOM sanitizer而不直接使用[innerHTML]。@GünterZöchbauer 在他的回答中建议使用safeHtml管道,这是清理内容的一种方法。以下指令是另一个指令:
import { Directive, ElementRef, Input, OnChanges, Sanitizer, SecurityContext,
SimpleChanges } from '@angular/core';
// Sets the element's innerHTML to a sanitized version of [safeHtml]
@Directive({ selector: '[safeHtml]' })
export class HtmlDirective implements OnChanges {
@Input() safeHtml: string;
constructor(private elementRef: ElementRef, private sanitizer: Sanitizer) {}
ngOnChanges(changes: SimpleChanges): any {
if ('safeHtml' in changes) {
this.elementRef.nativeElement.innerHTML =
this.sanitizer.sanitize(SecurityContext.HTML, this.safeHtml);
}
}
}
要使用的
<div [safeHtml]="myVal"></div>
Can't bind to 'safeHtml' since it isn't a known property of 'div'.
ng版本2.4.4
constructor( private sanitizer: Sanitizer) {}
并将结果绑定到所需的内容中,强烈建议不要使用ElementRef。
请参考其他最新的答案。
这对我<div innerHTML = "{{ myVal }}"></div>
有用:(Angular2,Alpha 33)
根据另一种SO:使用angular2将服务器中的HTML插入DOM(Angular2中的一般DOM操作),“ inner-html”等效于Angular 1.X中的“ ng-bind-html”
仅作一个完整的答案,如果您的html内容位于组件变量中,则还可以使用:
<div [innerHTML]=componementVariableThatHasTheHtml></div>
如果在这里我遗漏了一点,我深表歉意,但是我想推荐一种不同的方法:
我认为最好从服务器端应用程序返回原始数据并将其绑定到客户端的模板。由于您只从服务器返回json,因此请求更为灵活。
对我来说,如果您要做的只是从服务器获取html并将其“按原样”注入DOM,那么使用Angular似乎没有任何意义。
我知道Angular 1.x具有html绑定,但是我还没有在Angular 2.0中看到对应版本。他们可能稍后再添加。无论如何,我仍然会考虑为您的Angular 2.0应用提供数据API。
如果您感兴趣的话,这里有一些示例,其中包含一些简单的数据绑定:http : //www.syntaxsuccess.com/viewarticle/angular-2.0-examples
这里已经提供了简短的答案:使用<div [innerHTML]="yourHtml">
绑定。
但是,此处提到的其他建议可能会产生误导。当您绑定到诸如此类的属性时,Angular具有内置的清理机制。由于Angular不是专用的消毒库,因此对可疑内容过分热衷而不承担任何风险。例如,它将所有SVG内容清除为空字符串。
您可能会听到通过使用DomSanitizer
方法将内容标记为安全来“清理”内容的建议bypassSecurityTrustXXX
。还有建议使用管道来完成该任务,该管道通常称为safeHtml
。
所有这些都具有误导性,因为它实际上绕过了清理而不是清理您的内容。这可能是一个安全问题,因为如果您对用户提供的内容或不确定的任何内容执行此操作,则可能会遭受恶意代码攻击。
如果Angular通过其内置的清理功能删除了您需要的东西,那么您可以做的而不是禁用它,就是将实际的清理操作委派给擅长该任务的专用库。例如-DOMPurify。
我已经为其创建了一个包装器库,以便可以轻松地与Angular一起使用:https : //github.com/TinkoffCreditSystems/ng-dompurify
它还有一个管道以声明方式清理HTML:
<div [innerHtml]="value | dompurify"></div>
这里建议的管道的不同之处在于,它实际上是通过DOMPurify进行消毒的,因此适用于SVG。
要记住的一件事是DOMPurify非常适合清理HTML / SVG,而不是CSS。因此,您可以提供Angular的CSS清理程序来处理CSS:
import {NgModule, ɵ_sanitizeStyle} from '@angular/core';
import {SANITIZE_STYLE} from '@tinkoff/ng-dompurify';
@NgModule({
// ...
providers: [
{
provide: SANITIZE_STYLE,
useValue: ɵ_sanitizeStyle,
},
],
// ...
})
export class AppModule {}
它是内部的-hense ɵ
前缀,但是无论如何,这也是Angular团队在其自己的程序包中使用它的方式。该库还适用于Angular Universal和服务器端优化环境。
只需[innerHTML]
在HTML中使用attribute,如下所示:
<div [innerHTML]="myVal"></div>
您的组件中是否曾经包含过一些需要在模板中显示的html标记或实体的属性?传统的插值将不起作用,但是innerHTML属性绑定可以解决。
使用{{myVal}}
不能按预期工作!这会不会拿起像HTML标签<p>
,<strong>
等,它通过只作为字符串...
假设您的组件中包含以下代码:
const myVal:string ='<strong>Stackoverflow</strong> is <em>helpful!</em>'
如果使用{{myVal}}
,您将在视图中获得此信息:
<strong>Stackoverflow</strong> is <em>helpful!</em>
但是使用[innerHTML]="myVal"
可以使结果像预期的那样:
计算器是有帮助的!
您可以为.html中的样式,链接和HTML应用多个管道
<div [innerHTML]="announcementContent | safeUrl| safeHtml">
</div>
并在.ts管道中使用“ URL”消毒剂
import { Component, Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({ name: 'safeUrl' })
export class SafeUrlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
“ HTML”消毒剂的管道
import { Component, Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
这将在不影响任何样式和链接点击事件的情况下都适用
在AngularJS v2.1.1中工作
<div [innerHTML]="variable or htmlString">
</div>
<div _ngcontent-luf-0=""></div>
对我来说。该div
是空的。
如Angular 2文档所述,将元素动态添加到DOM的方法是使用@ Angular / core中的ViewContainerRef类。
您要做的是声明一个指令,该指令将实现ViewContainerRef并在DOM上充当占位符。
指示
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appInject]'
})
export class InjectDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
然后,在要注入组件的模板中:
的HTML
<div class="where_you_want_to_inject">
<ng-template appInject></ng-template>
</div>
然后,从注入的组件代码中,将注入包含所需HTML的组件:
import { Component, OnInit, ViewChild, ComponentFactoryResolver } from '@angular/core';
import { InjectDirective } from '../inject.directive';
import { InjectedComponent } from '../injected/injected.component';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
@ViewChild(InjectDirective) injectComp: InjectDirective;
constructor(private _componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
}
public addComp() {
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(InjectedComponent);
const viewContainerRef = this.injectComp.viewContainerRef;
const componentRef = viewContainerRef.createComponent(componentFactory);
}
public removeComp() {
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(InjectedComponent);
const viewContainerRef = this.injectComp.viewContainerRef;
const componentRef = viewContainerRef.remove();
}
}
我在Angular 2上添加了一个完全可用的演示应用程序,将组件动态添加到DOM演示中
您可以使用多种方法来实现该解决方案。如已批准的答案中所述,您可以使用:
<div [innerHTML]="myVal"></div>
根据您要实现的目标,您还可以尝试其他方法,例如javascript DOM(不推荐,DOM操作很慢):
介绍
<div id="test"></test>
零件
var p = document.getElementsById("test");
p.outerHTML = myVal;
getElementsById
或任何其他选择方法进行操作都是不好的,因为如果它们包含具有相同id(或其他条件)的元素,则它们可能捕获属于完全不同的组件的元素。
我们总是可以将html内容传递给innerHTML
属性以呈现html动态内容,但是动态html内容也可以被感染或恶意感染。因此,在将动态内容传递给innerHTML
我们之前,应始终确保对内容进行了清理(使用DOMSanitizer
),以便我们可以逃脱所有恶意内容。
尝试以下管道:
import { Pipe, PipeTransform } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
@Pipe({name: 'safeHtml'})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {
}
transform(value: string) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
Usage:
<div [innerHTML]="content | safeHtml"></div>
style: background-color
,所有东西都可能被剥夺,因此最好一开始就开始使用它,否则以后会感到非常困惑。
如果您希望在Angular 2或Angular 4中使用它,并且还希望保留内联CSS,则可以使用
<div [innerHTML]="theHtmlString | keepHtml"></div>
如果在角度(或任何框架)应用程序中有模板,并且您通过HTTP请求/响应从后端返回HTML模板,则您在前端和后端之间混合了模板。
为什么不只将模板化的东西留在前端(我建议这样做)还是留在后端(相当不透明的imo)?
而且,如果您将模板保留在前端,为什么不只使用JSON响应对后端的请求。您甚至不必实现RESTful结构,但是将模板放在一边可以使您的代码更加透明。
当其他人不得不处理您的代码时(甚至您自己在一段时间后重新输入自己的代码),这将获得回报!
如果做得正确,您将拥有带有小型模板的小型组件,而最重要的是,如果您的代码是imba,则不懂编码语言的人将能够理解您的模板和您的逻辑!因此,另外,请使函数/方法尽可能小。您最终会发现,与大型函数/方法/类相比,维护,重构,查看和添加功能要容易得多,并且在前端和后端之间混合模板和逻辑-并在后端保留尽可能多的逻辑如果您的前端需要更灵活(例如,编写android前端或切换到其他前端框架)。
哲学,人:)
ps:您不必实施100%干净的代码,因为这非常昂贵-尤其是如果您必须激励团队成员;)但是:您应该在更干净的代码方法和所拥有的方法之间找到一个好的平衡(也许是已经很干净了)
如果可以,请检查该书,并让它进入您的灵魂:https : //de.wikipedia.org/wiki/Clean_Code