qrcode

马上订阅,开启修仙之旅

Angular 组件样式

ngClass

通常情况下,要为某个元素添加指定样式,我们可以直接这样做:

1
<button class="btn btn-primary">提交</button>

但某些时候我们需要根据不同的条件,为指定元素应用不同的样式。对于这种场景,我们可以使用属性绑定,如:

1
2
3
<button class="btn" [class.btn-primary]="true" type="submit">
提交
</button>

但有时候,一个元素可能拥有多种状态样式,这时我们就可以使用 ngClass 指令。传递给 ngClass 指令的表达式的数据类型可以是:对象、数组或字符串。

接下来让我们来分别看一下具体的使用示例:

传递样式数组

1
<button [ngClass]="['btn', 'btn-primary']">提交</button>

Angular 将会接收传递给 ngClass 指令的样式数组,然后把对应的样式应用到指定的元素上。下面是最终显示结果:

1
<button class="btn btn-primary">提交</button>

传递字符串

1
2
3
<button [ngClass]="'btn btn-primary'" type="submit" (click)="submit()">
提交
</button>

传递样式配置对象

1
2
3
<button [ngClass]="{ btn: true, 'btn-primary': true }">
提交
</button>

样式配置对象的键为样式类的名称,而对应的值是布尔值或布尔表达式,即用于表示是否应用对应的样式类。

ngClass 综合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Component({
selector: 'app-root',
template: `
<button (click)="toggleState()">切换状态</button>
<button [ngClass]="calculateClasses()" (click)="submit()">
提交
</button>
`})
export class AppComponent {
stateFlag = false;
toggleState() {
this.stateFlag = !this.stateFlag;
}

submit() {
console.log('Button submitted');
}

calculateClasses() {
return {
btn: true,
'btn-primary': true,
'btn-extra-class': this.stateFlag
};
}
}

ngStyle

传递样式对象

1
<button [ngStyle]="{background: 'red'}">提交</button>

以下是最终的显示结果:

1
<button style="background: red">提交</button>

类似于 ngClass 综合示例的使用方式,当 ngStyle 指令的配置对象过大,我们可以通过组件的方法来获取样式配置对象,比如:

1
<button [ngStyle]="calculateStyles()">提交</button>

视图封装

Emulated

app.component.html

1
2
3
4
5
6
7
@Component({
selector: 'my-app',
styleUrls:['./app.component.css'],
template: `
<button class="red-button">Button</button>
`})
export class AppComponent {}

app.component.css

1
2
3
.red-button {
background:red;
}

以上代码成功运行后,页面生成的 HTML 结构:

1
2
3
4
<my-app _nghost-c12="" ng-version="6.0.0">
<button _ngcontent-c12="" class="red-button">按钮1</button>
</my-app>
<button class="red-button">按钮2</button>

当你看到页面的显示结果,你可能会感到惊讶,按钮2 的背景颜色没有变成红色,这时我们来查看一下模板内红色按钮所应用的样式:

1
2
3
.red-button[_ngcontent-c12] {
background:red;
}

除此之外,从页面生成的 HTML 结构,我们也发现了 _nghost-c12_ngcontent-c12 这些奇怪的属性。

那么这些属性是什么呢,它们有什么用?为了弄清楚这些属性,我们再新建一个 BlueButtonComponent 组件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component({
selector: 'blue-button',
template: `
<h3>蓝色按钮组件</h3>
<button class="blue-button">蓝色按钮</button>
`,
styles: [`
.blue-button {
background:blue;
}
`]
})
export class BlueButtonComponent { }

之后,我们在根组件中使用新建的 BlueButtonComponent 组件:

1
2
3
4
5
6
7
8
@Component({
selector: 'my-app',
styleUrls:['./app.component.css'],
template: `
<button class="red-button">红色按钮</button>
<blue-button></blue-button>
`})
export class AppComponent { }

以上代码成功运行后,页面生成以下 HTML 代码:

1
2
3
4
5
6
7
<my-app _nghost-c17="" ng-version="6.0.0">
<button _ngcontent-c17="" class="red-button">红色按钮</button>
<blue-button _ngcontent-c17="" _nghost-c18="">
<h2 _ngcontent-c18="">蓝色按钮组件</h2>
<button _ngcontent-c18="" class="blue-button">蓝色按钮</button>
</blue-button>
</my-app>

我们注意到 blue-button 元素,新增了 _nghost-c18 host 属性,另外也存在一个 _ngcontent-c17 属性。

host 元素与模板元素属性工作原理

  • 当应用程序启动的时候,宿主元素将会拥有一个唯一的属性,该属性的值取决于组件的处理顺序,比如 _nghost-c0, _nghost-c1
  • 每个组件内的元素,将会应用唯一的属性,比如 _ngcontent-c0, _ngcontent-c1

然而这些属性,是如何启动视图封装的作用呢?

1
2
3
4
5
6
7
8
9
10
11
/* Style 1 - a simple CSS style, 
with low specificy and easilly overridable */
.blue-button {
background: blue;
}

/* Style 2 - a similar style, with a much higher
specificity and much harder to override */
.blue-button[_ngcontent-c1] {
background: blue;
}

:host 伪类选择器

有些时候,我们只想为宿主元素设置某些样式,但却不想影响到宿主元素下的其它元素。这时我们可以使用 :host 选择器:

1
2
3
4
5
6
/* styles applied directly to the ap-root element only */
:host {
border: 2px solid dimgray;
display: block;
padding: 20px;
}

通过 :host 选择器我们可以确保上面的样式只被应用到宿主元素上,:host 选择器在运行时会转换为以下样式:

1
2
3
4
5
6
7
<style>
[_nghost-c0] {
border: 2px solid dimgray;
display: block;
padding: 20px;
}
</style>

此外 :host 选择器也可以结合其它的选择器,比如:

1
2
3
4
/* let's add another style to app.conmponent.css */
:host h2 {
color: red;
}

以上样式在运行时,将生成以下样式:

1
2
3
4
5
6
<style>
....
[_nghost-c0] h2[_ngcontent-c0] {
color: red;
}
</style>

很明显,特定的作用域相关的属性,也会被应用到嵌入的选择器上,从而确保样式只局部应用于特定的模板。但如果我们想要设置所有 h2 标签的元素呢,这里仍有对应的方法。

:: ng-deep 伪类选择器

1
2
3
:host ::ng-deep h2 {
color: red;
}

以上样式在运行时,将生成以下样式:

1
2
3
[_nghost-c0]  h2 {
color: red;
}

:host-context 伪类选择器

:host-context 伪类选择器对于开发主题样式很有用,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component({
selector: 'themeable-button',
template: `
<button class="btn btn-theme">可配主题按钮</button>
`,
styles: [`
:host-context(.red-theme) .btn-theme {
background: red;
}
:host-context(.blue-theme) .btn-theme {
background: blue;
}
`]
})
export class ThemeableButtonComponent { }

ThemeableButtonComponent 的使用示例如下:

1
2
3
<div class="blue-theme">
<themeable-button></themeable-button>
</div>

欢迎小伙伴们订阅前端修仙之路,及时阅读 Angular、RxJS、TypeScript 和 Node.js 最新文章。

qrcode