Angular 2 - innerHTML 样式
Angular 2 - innerHTML styling
我从 HTTP 调用中获取了 HTML 代码块。我将 HTML 块放在一个变量中,并使用 [innerHTML] 将其插入我的页面,但我无法为插入的 HTML 块设置样式。有人对我如何实现这一目标有任何建议吗?
@Component({
selector: 'calendar',
template: '<div [innerHTML]="calendar"></div>',
providers: [HomeService],
styles: [`h3 { color: red; }`]
})
我要设置样式的HTML是变量“calendar”中包含的块。
更新 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 类 添加到 HTML 它添加到 DOM 以模拟阴影 DOM CSS 封装以防止组件进出样式。 Angular 还会重写您添加的 CSS 以匹配这些添加的 类。对于使用 [innerHTML]
添加的 HTML,这些 类 未添加并且重写的 CSS 不匹配。
作为解决方法尝试
- 为CSS 添加到组件
/* :host /deep/ mySelector { */
:host ::ng-deep mySelector {
background-color: blue;
}
- 为 CSS 添加到
index.html
/* body /deep/ mySelector { */
body ::ng-deep mySelector {
background-color: green;
}
>>>
(和等价物/deep/
,但 /deep/
与 SASS 配合使用效果更好)和 ::shadow
已添加到 2.0.0-beta.10 .它们类似于影子 DOM CSS 组合器(已弃用)并且仅适用于 encapsulation: ViewEncapsulation.Emulated
,这是 Angular2 中的默认值。它们也可能与 ViewEncapsulation.None
一起使用,但随后仅被忽略,因为它们不是必需的。
在支持跨组件样式的更高级功能之前,这些组合器只是一个中间解决方案。
另一种方法是使用
@Component({
...
encapsulation: ViewEncapsulation.None,
})
对于阻止您的 CSS 的所有组件(取决于您添加 CSS 的位置以及您要设置样式的 HTML 的位置 - 可能是 您应用程序中的所有 个组件)
更新
如果您尝试为 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
以便您可以继续使用 /deep/ 进行开发。
Günter Zöchbauer 推荐的版本很好用,但我还有一个补充。在我的例子中,我有一个无样式的 html-element 并且我不知道如何设置它的样式。因此,我设计了一个管道来为其添加样式。
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-element 添加样式:
<span [innerhtml]="Variable | StyleClass: 'margin': '0'"> </span>
与:
Variable = '<p> Test </p>'
任何想要的人只需将某种样式应用于内部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 个问题:
ViewEncapsulation.NONE
导致我的组件出现其他样式问题
- 我的“安全”html 似乎无法使用 css 变量,即 var(--blue)
这对我有用(无需更改任何其他内容): InsertAdjacentHTML
模板:
<div id=template></div>
代码:
ngOnInit() {
const el = document.getElementById('template');
el.insertAdjacentHTML('afterbegin', `<span style="color: var(--blue)">hello</span>`);
}
免责声明:在我的例子中,我从配置文件中解析 html。您不会希望用户输入 html.
走这条路
最简单直接的方法是使用位于 angular 项目 src 文件夹中的全局样式文件。
假设组件选择器是:app-my-component
在 app-my-component 模板中向承载 innerHtml 内容的元素添加一个 class:
<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
如果您的动态样式有限,则使用 inline CSS variables 是替代解决方案。
即
// 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);
}
我从 HTTP 调用中获取了 HTML 代码块。我将 HTML 块放在一个变量中,并使用 [innerHTML] 将其插入我的页面,但我无法为插入的 HTML 块设置样式。有人对我如何实现这一目标有任何建议吗?
@Component({
selector: 'calendar',
template: '<div [innerHTML]="calendar"></div>',
providers: [HomeService],
styles: [`h3 { color: red; }`]
})
我要设置样式的HTML是变量“calendar”中包含的块。
更新 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 类 添加到 HTML 它添加到 DOM 以模拟阴影 DOM CSS 封装以防止组件进出样式。 Angular 还会重写您添加的 CSS 以匹配这些添加的 类。对于使用 [innerHTML]
添加的 HTML,这些 类 未添加并且重写的 CSS 不匹配。
作为解决方法尝试
- 为CSS 添加到组件
/* :host /deep/ mySelector { */
:host ::ng-deep mySelector {
background-color: blue;
}
- 为 CSS 添加到
index.html
/* body /deep/ mySelector { */
body ::ng-deep mySelector {
background-color: green;
}
>>>
(和等价物/deep/
,但 /deep/
与 SASS 配合使用效果更好)和 ::shadow
已添加到 2.0.0-beta.10 .它们类似于影子 DOM CSS 组合器(已弃用)并且仅适用于 encapsulation: ViewEncapsulation.Emulated
,这是 Angular2 中的默认值。它们也可能与 ViewEncapsulation.None
一起使用,但随后仅被忽略,因为它们不是必需的。
在支持跨组件样式的更高级功能之前,这些组合器只是一个中间解决方案。
另一种方法是使用
@Component({
...
encapsulation: ViewEncapsulation.None,
})
对于阻止您的 CSS 的所有组件(取决于您添加 CSS 的位置以及您要设置样式的 HTML 的位置 - 可能是 您应用程序中的所有 个组件)
更新
如果您尝试为 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
以便您可以继续使用 /deep/ 进行开发。
Günter Zöchbauer 推荐的版本很好用,但我还有一个补充。在我的例子中,我有一个无样式的 html-element 并且我不知道如何设置它的样式。因此,我设计了一个管道来为其添加样式。
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-element 添加样式:
<span [innerhtml]="Variable | StyleClass: 'margin': '0'"> </span>
与:
Variable = '<p> Test </p>'
任何想要的人只需将某种样式应用于内部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 个问题:
ViewEncapsulation.NONE
导致我的组件出现其他样式问题- 我的“安全”html 似乎无法使用 css 变量,即 var(--blue)
这对我有用(无需更改任何其他内容): InsertAdjacentHTML
模板:
<div id=template></div>
代码:
ngOnInit() {
const el = document.getElementById('template');
el.insertAdjacentHTML('afterbegin', `<span style="color: var(--blue)">hello</span>`);
}
免责声明:在我的例子中,我从配置文件中解析 html。您不会希望用户输入 html.
走这条路最简单直接的方法是使用位于 angular 项目 src 文件夹中的全局样式文件。
假设组件选择器是:app-my-component
在 app-my-component 模板中向承载 innerHtml 内容的元素添加一个 class:
<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
如果您的动态样式有限,则使用 inline CSS variables 是替代解决方案。
即
// 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);
}