ngClass

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

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

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

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

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

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

传递样式数组

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

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

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

传递字符串

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

传递样式配置对象

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

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

ngClass 综合示例

@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

传递样式对象

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

以下是最终的显示结果:

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

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

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

视图封装

Emulated

app.component.html

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

app.component.css

.red-button {
   background:red;
}

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

<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 的背景颜色没有变成红色,这时我们来查看一下模板内红色按钮所应用的样式:

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

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

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

@Component({
  selector: 'blue-button',
  template: `
      <h3>蓝色按钮组件</h3>
      <button class="blue-button">蓝色按钮</button>
  `,
  styles: [`
      .blue-button {
          background:blue;
      }
  `]
})
export class BlueButtonComponent  { }

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

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

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

<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

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

/* 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 选择器:

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

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

<style>
  [_nghost-c0] {
    border: 2px solid dimgray;
    display: block;
    padding: 20px;
  }
</style>

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

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

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

<style>
   ....
  [_nghost-c0]  h2[_ngcontent-c0] {
    color: red;
  }
</style>

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

:: ng-deep 伪类选择器

:host ::ng-deep h2 {
    color: red;
}

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

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

:host-context 伪类选择器

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

@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 的使用示例如下:

<div class="blue-theme">
   <themeable-button></themeable-button>
</div>
收藏 打印