Angular 2 - innerHTML样式

我从HTTP调用中获得了大量的HTML代码。我把HTML块放在一个变量,并将它插入到我的页面[innerHTML],但我不能样式插入的HTML块。有人有什么建议吗?

@Component({
selector: 'calendar',
template: '<div [innerHTML]="calendar"></div>',
providers: [HomeService],
styles: [`h3 { color: red; }`]
})

我想要样式的HTML是包含在“日历”变量中的块。

170342 次浏览

更新2 ::slotted

现在所有新浏览器都支持::slotted,并且可以与ViewEncapsulation.ShadowDom一起使用

https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted

更新1::ng-deep

/deep/已弃用,并被::ng-deep取代。

::ng-deep也已经被标记为弃用,但还没有可用的替换。

当所有浏览器都正确支持ViewEncapsulation.Native并支持跨阴影DOM边界的样式化时,::ng-deep可能会停止使用。

原始

Angular将各种CSS类添加到它添加到DOM的HTML中,以模拟影子DOM CSS封装,以防止样式流入和流出组件。Angular还会重写你添加的CSS来匹配这些添加的类。对于使用[innerHTML]添加的HTML,这些类没有添加,重写的CSS也不匹配。

作为一个变通的尝试

  • 为CSS添加到组件
/* :host /deep/ mySelector { */
:host ::ng-deep mySelector {
background-color: blue;
}
  • for CSS添加到index.html
/* body /deep/ mySelector { */
body ::ng-deep mySelector {
background-color: green;
}

>>>(和等价的/deep/,但/deep/在SASS中更好地工作)和::shadow在2.0.0-beta.10中添加。它们类似于shadow DOM CSS组合子(已弃用),并且只适用于Angular2中的默认encapsulation: ViewEncapsulation.Emulated。它们可能也适用于ViewEncapsulation.None,但只是因为它们不是必需的而被忽略。 在支持更高级的跨组件样式化特性之前,这些组合符只是一个中间解决方案

另一种方法是使用

@Component({
...
encapsulation: ViewEncapsulation.None,
})

对于所有阻碍CSS的组件(取决于你添加CSS的位置以及你想要设置样式的HTML的位置——可能是应用程序中的所有组件)

更新

< a href = " https://plnkr.co/edit/ZHByFR?p=preview" rel="noreferrer">活塞 . p=preview" rel="noreferrer">

如果你想在Angular组件中动态添加HTML元素,这可能会有帮助:

// inside component class...
    

constructor(private hostRef: ElementRef) { }
    

getContentAttr(): string {
const attrs = this.hostRef.nativeElement.attributes
for (let i = 0, l = attrs.length; i < l; i++) {
if (attrs[i].name.startsWith('_nghost-c')) {
return `_ngcontent-c${attrs[i].name.substring(9)}`
}
}
}
    

ngAfterViewInit() {
// dynamically add HTML element
dynamicallyAddedHtmlElement.setAttribute(this.getContentAttr(), '')
}

我的猜测是,这个属性的约定不能保证在不同版本的Angular之间是稳定的,所以当升级到新版本的Angular时,这个解决方案可能会遇到问题(尽管,在这种情况下,更新这个解决方案可能是微不足道的)。

你需要遵循的简单解决方案是

import { DomSanitizer } from '@angular/platform-browser';


constructor(private sanitizer: DomSanitizer){}


transformYourHtml(htmlTextWithStyle) {
return this.sanitizer.bypassSecurityTrustHtml(htmlTextWithStyle);
}

我们经常从CMS中导入[innerHTML]="content.title"内容。我们将必要的类放在应用程序的根styles.scss文件中,而不是放在组件的scss文件中。我们的CMS特意剥离了内联样式,所以我们必须准备好作者可以在其内容中使用的类。记住在模板中使用\{\{content.title}}将不会从内容中呈现html。

如果你使用sass作为样式预处理器,你可以通过以下方式切换回原生sass编译器:

npm install node-sass --save-dev

这样你就可以继续用/深/来发展。

Günter Zöchbauer推荐的版本很好,但我要做一个补充。在我的例子中,我有一个没有样式的html元素,我不知道如何样式它。因此,我设计了一个管道来添加样式。

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




@Pipe({
name: 'StyleClass'
})
export class StyleClassPipe implements PipeTransform {


constructor(private sanitizer: DomSanitizer) { }
transform(html: any, styleSelector: any, styleValue: any): SafeHtml {
const style = ` style = "${styleSelector}: ${styleValue};"`;
const indexPosition = html.indexOf('>');
const newHtml = [html.slice(0, indexPosition), style, html.slice(indexPosition)].join('');
return this.sanitizer.bypassSecurityTrustHtml(newHtml);
}


}

然后你可以像这样给任何html元素添加样式:

<span [innerhtml]="Variable | StyleClass: 'margin': '0'"> </span>

:

Variable = '<p> Test </p>'

对于任何想要对innerHTML应用特定样式的人来说:

遵循创建一个安全的HTML管道

你可以像这样用CSS样式连接你的HTML字符串:

return this.sanitizer.bypassSecurityTrustHtml(value+='<style type="text/css">.image img { width: 100% }</style>');

value来自transform(value,…args)

我最初走了this.sanitizer.bypassSecurityTrustHtml()路线,并将封装设置为ViewEncapsulation.NONE,但有2个问题:

  1. ViewEncapsulation.NONE在我的组件中导致其他样式问题
  2. 我的“safe"HTML似乎不能与CSS变量一起工作,即var(——蓝色)

这对我来说很有效(不需要改变任何其他东西): InsertAdjacentHTML

模板:

<div id=template></div>

代码:

ngOnInit() {
const el = document.getElementById('template');
el.insertAdjacentHTML('afterbegin', `<span style="color: var(--blue)">hello</span>`);
}

免责声明:在我的情况下,我是从配置文件解析html。对于用户输入的html,您不会希望走这条路线。

最简单、最直接的方法是使用angular project src文件夹中的全局样式文件。

假设组件选择器是:app-my-component

在app-my-component模板中,向innerHtml内容所在的元素中添加一个类:

<div class="innerhtml-class" [innerHTML]="variable.innerHtml"></div>

添加到全局样式文件:

app-my-component {
.innerhtml-class {
declaration goes here
}
}

使用下面的方法在innerhtml中允许CSS样式。

import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
.
.
.
.
html: SafeHtml;


constructor(protected _sanitizer: DomSanitizer) {
this.html = this._sanitizer.bypassSecurityTrustHtml(`
<html>
<head></head>
<body>
<div style="display:flex; color: blue;">
<div>
<h1>Hello World..!!!!!</h1>
</div>
</div>
</body>
</html>`);
}

示例代码 stackblitz

使用下面的方法直接在HTML中写入。 https://gist.github.com/klihelp/4dcac910124409fa7bd20f230818c8d1 < / p >

如果你的动态样式有限,使用内联CSS变量是另一种解决方案。

即。

// file.ts
someVarWithHtml = 'Hello <span class="dynamic">World</span>';


// file.ng.html
<div [style]="'--my-var: ' + value"
[innerHTML]="someVarWithHtml"></div>


// style.css
.dynamic {
background: var(--my-var);
}