# 属性型指令

使用属性型指令,可以更改 DOM 元素和 Angular 组件的外观或行为。

TIP

包含本指南中代码片段的可工作范例,参阅现场演练/ 下载范例

# 建立属性型指令

本节将引导你创建“突出显示”指令,该指令会将宿主元素的背景色设置为黄色。

  • 要创建指令,请使用 CLI 命令 ng generate directive
ng generate directive highlight

CLI 创建 src/app/highlight.directive.ts以及相应的测试文件 src/app/highlight.directive.spec.ts,并在 AppModule中声明此指令类。

CLI 生成默认的 src/app/highlight.directive.ts,如下所示:

src/app/highlight.directive.ts

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

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

@Directive()装饰器的配置属性会指定指令的 CSS 属性选择器 [appHighlight]

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

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

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

src/app/highlight.directive.ts

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

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

指令不支持名称空间。

src/app/app.component.avoid.html (unsupported)

<p app:Highlight>This is invalid</p>

# 应用属性型指令

  • 要使用 HighlightDirective,请将 &lt;p&gt;元素添加到 HTML 模板中,并以伪指令作为属性。

src/app/app.component.html

<p appHighlight>Highlight me!</p>

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

# 处理用户事件

本节会展示如何检测用户何时将鼠标移入或移出元素以及如何通过设置或清除突出显示颜色来进行响应。

  • 从 '@angular/core' 导入 HostListener

src/app/highlight.directive.ts (imports)

import { Directive, ElementRef, HostListener } from '@angular/core';
  • 添加两个事件处理程序,它们会在鼠标进入或离开时做出响应,每个事件处理程序都带有 @HostListener()装饰器。

src/app/highlight.directive.ts (mouse-methods)

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

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

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

要订阅本属性型指令宿主 DOM 元素上的事件(在本例中是 &lt;p&gt;),可以使用 @HostListener()装饰器。

处理程序会委托给一个辅助方法 highlight(),该方法会设置宿主 DOM 元素 el的颜色。

完整的指令如下:

src/app/highlight.directive.ts

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

  constructor(private el: ElementRef) { }

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

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

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

}

当指针悬停在 p 元素上时,背景颜色就会出现;而当指针移出时,背景颜色就会消失。

Second Highlight

# 将值传递给属性型指令

本节将引导你在应用 HighlightDirective时设置突出显示颜色。

  • highlight.directive.ts中,从 @angular/core导入 Input

src/app/highlight.directive.ts (imports)

import { Directive, ElementRef, HostListener, Input } from '@angular/core';
  • 添加一个 appHighlight@Input()属性。

src/app/highlight.directive.ts

@Input() appHighlight = '';

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

  • app.component.ts,将 color属性添加到 AppComponent

src/app/app.component.ts (class)

export class AppComponent {
  color = 'yellow';
}
  • 要同时应用指令和颜色,请通过 appHighlight指令选择器使用属性绑定,将其设置为 color

src/app/app.component.html (color)

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

[appHighlight]属性绑定执行两项任务:

  • 将突出显示指令应用于 &lt;p&gt;元素

  • 通过属性绑定设置指令的突出显示颜色

# 通过用户输入来设置值

本节指导你添加单选按钮,将你选择的颜色绑定到 appHighlight指令。

  • 将标记添加到 app.component.html以选择颜色,如下所示:

src/app/app.component.html (v2)

<h1>My First Attribute Directive</h1>

<h2>Pick a highlight color</h2>
<div>
  <input type="radio" name="colors" (click)="color='lightgreen'">Green
  <input type="radio" name="colors" (click)="color='yellow'">Yellow
  <input type="radio" name="colors" (click)="color='cyan'">Cyan
</div>
<p [appHighlight]="color">Highlight me!</p>
  • 修改 AppComponent.color,使其没有初始值。

src/app/app.component.ts (class)

export class AppComponent {
  color = '';
}
  • highlight.directive.ts中,修改 onMouseEnter方法,让它首先尝试使用 appHighlight进行高亮显示,如果 appHighlightundefined,则回退为 red

src/app/highlight.directive.ts (mouse-enter)

@HostListener('mouseenter') onMouseEnter() {
  this.highlight(this.appHighlight || 'red');
}
  • 启动本应用的开发服务器,以验证用户可以通过单选按钮选择颜色。

Animated gif of the refactored highlight directive changing color according to the radio button the user selects

# 绑定到第二个属性

本节将指导你配置应用程序,以便开发人员可以设置默认颜色。

  • 将第二个 Input()属性 defaultColor添加到 HighlightDirective

src/app/highlight.directive.ts (defaultColor)

@Input() defaultColor = '';
  • 修改指令的 onMouseEnter,使其首先尝试使用 appHighlight进行突出显示,然后尝试 defaultColor,如果两个属性都 undefined,则变回 red

src/app/highlight.directive.ts (mouse-enter)

@HostListener('mouseenter') onMouseEnter() {
  this.highlight(this.appHighlight || this.defaultColor || 'red');
}
  • 若要绑定到 AppComponent.color并回退为默认颜色“紫罗兰(violet)”,请添加以下 HTML。在这里,defaultColor绑定没有使用方括号 [],因为它是静态的。

src/app/app.component.html (defaultColor)

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

与组件一样,你可以将指令的多个属性绑定添加到宿主元素上。

如果没有默认颜色(defaultColor)绑定,则默认为红色。当用户选择一种颜色时,所选的颜色将成为突出显示的颜色。

Animated gif of final highlight directive that shows red color with no binding and violet with the default color set. When user selects color, the selection takes precedence.

# 通过 NgNonBindable停用 Angular 处理过程

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

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

src/app/app.component.html

<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>

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

src/app/app.component.html

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

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

Last Updated: 5/13/2023, 10:57:08 AM