Angular 入门基础(第八篇) 如何自定义指令 (Directive)

581 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天。点击查看活动详情

指令是为 Angular 应用程序中的元素添加额外行为的类。使用 Angular 的内置指令,你可以管理表单、列表、样式以及要让用户看到的任何内容。

Angular 指令的不同类型如下:

指令类型详情
组件带有模板的指令。这种指令类型是最常见的指令类型。
属性型指令更改元素、组件或其他指令的外观或行为的指令。
结构型指令通过添加和删除 DOM 元素来更改 DOM 布局。

内置属性型指令

属性型指令会监听并修改其它 HTML 元素和组件的行为、AttributeProperty

许多 NgModule(比如 RouterModuleFormsModule 都定义了自己的属性型指令。最常见的属性型指令如下:

  • NgClass 添加和删除一组 CSS 类。
  • NgStyle 添加和删除一组 HTML 样式。
  • NgModel 将双向数据绑定添加到 HTML 表单元素。

内置结构型指令

结构型指令的职责是 HTML 布局。它们塑造或重塑 DOM 的结构,这通常是通过添加、移除和操纵它们所附加到的宿主元素来实现的。

  • NgIf 有条件地从模板创建或销毁子视图。
  • NgFor 为列表中的每个条目重复渲染一个节点。
  • NgSwitch 一组在备用视图之间切换的指令。

自定义指令

ng generate directive highlight
import { Directive } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
  constructor() { }
}
  • @Directive() 装饰器的配置属性会指定指令的 CSS 属性选择器 [appHighlight]

  • @angular/core 导入 ElementRefElementRefnativeElement 属性会提供对宿主 DOM 元素的直接访问权限。

  • 在指令的 constructor() 中添加 ElementRef 以注入对宿主 DOM 元素的引用,该元素就是 appHighlight 的作用目标。

HighlightDirective 类中添加逻辑,将背景设置为黄色。

import { Directive, ElementRef } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
    constructor(private el: ElementRef) {
       this.el.nativeElement.style.backgroundColor = 'yellow';
    }
}

应用属性型指令

Angular 会创建 HighlightDirective 类的实例,并将 <p> 元素的引用注入到该指令的构造函数中,它会将 <p> 元素的背景样式设置为黄色。

<p appHighlight>Highlight me!</p>

处理用户事件

'@angular/core' 导入 HostListener

添加两个事件处理程序,它们会在鼠标进入或离开时做出响应,每个事件处理程序都带有 @HostListener() 装饰器。

import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class TestDirective {
  constructor(private el: ElementRef) {
    el.nativeElement.style.backgroundColor = 'red';
  }

  @HostListener('mouseenter') onMouseEnter(): void {
    this.highlight('yellow');
  }

  @HostListener('mouseleave') onMouseLeave(): void {
    this.highlight('red');
  }

  private highlight(color: string): void {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

添加一个 @Input() 属性。

@Input() 装饰器会将元数据添加到此类,以便让该指令的 appHighlight 属性可用于绑定。

要同时应用指令和颜色,请通过 appHighlight 指令选择器使用属性绑定,将其设置为 color

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {

  constructor(private el: ElementRef) { }

  @Input() defaultColor = '';

  @Input() appHighlight = '';

  @HostListener('mouseenter') onMouseEnter() {
    this.highlight(this.appHighlight || this.defaultColor || 'red');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

<p [appHighlight]="color" defaultColor="violet">
  Highlight me too!
</p>

通过 NgNonBindable 停用 Angular 处理过程

要防止在浏览器中进行表达式求值,请将 ngNonBindable 添加到宿主元素。ngNonBindable 会停用模板中的插值、指令和绑定。

在下面的示例中,表达式 {{ 1 + 1 }} 的渲染方式会和在代码编辑器的一样,而不会显示 2。

<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>

ngNonBindable 应用于元素将停止对该元素的子元素的绑定。但是,ngNonBindable 仍然允许指令在应用 ngNonBindable 的元素上工作。在以下示例中,appHighlight 指令仍处于活跃状态,但 Angular 不会对表达式 {{ 1 + 1 }} 求值。

<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">{{ 1 +1 }}, but will highlight yellow.
</div>

如果将 ngNonBindable 应用于父元素,则 Angular 会禁用该元素的子元素的任何插值和绑定,比如属性绑定或事件绑定。