Angular 碎片 —— 自定义Directive

殳越
2023-12-01

目录

前言

代码预览

代码详解


前言

我们知道,AngularJS框架中,directive是一个重要的概念,是代码重用的基础。不过,该框架中directive的用法和配置稍显复杂。1.6版本后定义了新的component方法后,组件化编程相对更自然些。到了Angular框架中,component开始大行其道,出色的设计思想让组件化编程更为自然和易用了,而directive似乎销声匿迹了。

事实上,在Angular中,Directive的概念依然存在,Component就是一种特殊的Directive。只不过前者必须要提供视图,即Template;后者则不需要一定提供。通常情况下,非Component的Directive用于HTML标签的属性,标签可以是HTML原生的,也可以是其他Component,用途是赋予宿主标签某种行为。

本文介绍学习如何自定义一个Angular Directive。示例代码的基本结构采用了Angular官方的quickstart package,可以从官网下载。本文的示例代码可以在这里找到。

代码预览

基本的Directive语法可以从官方文档找到,这里先给出总体的代码,然后依次按需解释。

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

@Directive({
  selector: '[craftMan]'
})
export class CraftManDirective {

  private colors: string[] = [
    'darksalmon', 'hotpink', 'lightskyblue', 'goldenrod', 'peachpuff',
    'mediumspringgreen', 'cornflowerblue', 'blanchedalmond', 'lightslategrey'
  ];
  @HostBinding('style.color') color: string;
  @HostBinding('style.border-color') borderColor: string;
  @HostBinding('class.grey-cat') isGrey = true;

  @HostListener('mouseover') newColor() {
    const colorIndex = Math.floor(Math.random() * this.colors.length);
    this.color = this.borderColor = this.colors[colorIndex];
  }

  @Input() set craftMan(value) {
    this.isGrey = value;
  }
  constructor() { }

}

我们的示例Directive的选择器为[craftMan], 在相应的HTML文件里,使用的方式如下:

<div [craftMan]="getFlag()" style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <img width="300" alt="Angular Logo" src=">
</div>

可以看到,这个Directive有一个输入,其值为函数getFlag的返回值。该函数的定义如下:

private seed: number = 0;

constructor() {
    this.seed =  Math.floor(Math.random() * 10);
}

public getFlag(): boolean {
    return this.seed % 2 == 0;
}

逻辑很简单,随机生成的seed值为偶数就返回true,否则返回false。下面来详细解释每个部分。

代码详解

前面说过,Directive通常附着在某个HTML标签上,用于改变这个标签(原生或自定义)的某些行为。那么其附着的标签就是它的宿主(Host)。这里的“某些行为”,可以是宿主的某些属性,比如class,style,value等等;也可以是宿主的某些事件,比如click,mouseover,input等等。前者可以用@HostBinding注解实现,后者则对应@HostListener注解。

以上面代码中第三个@HostBinding注解为例,它将isGrey变量绑定到宿主的名为grey-cat的class属性上,其含义是,当该变量为true时,就在宿主上应用grey-cat样式,否则不应用。这里isGrey有个默认值true,当然也可以在后续的逻辑中改变它,但也可以依赖其他组件的输入。比如:

@Input() set craftMan(value) {
    this.isGrey = value;
}

这里使用@Input注解将传递给Directive的值设置到isGrey变量。输入的值即来自应用Directive的地方:[craftMan]=“getFlag()”

因此,运行的结果是,每次刷新页面,宿主元素会随机显示灰色或者透明色。

再来看@HostListener注解,也比较简单。上述代码将宿主的mouseover事件,绑定到newColor函数,当鼠标已过宿主元素时,就执行该函数。我们看到,执行的结果是把color变量设置为一个随机的颜色值,这个值已经通过@HostBinding注解绑定到宿主的color style上。因此,当鼠标移过时,宿主的字体会随机改变一种颜色。

另外有几点值得一提。如果我们想访问Directive所在宿主的元素对象,可以在构造器中获得引用:

constructor(el: ElementRef) {
   el.nativeElement.style.backgroundColor = 'yellow';
}

针对@HostListener注解,有人可能会问,为什么不用DOM API直接去写事件处理函数呢?有一下三点理由:

  • 直接去写要确保方式正确
  • 为了防止内存泄露,当Directive销毁时,你需要把listener从宿主解开
  • 直接操作DOM API不是好的编码习惯

以上就是Angular Directive的基本用法,如果需要更加深入,可以参考官方文档:

https://angular.io/guide/attribute-directives

https://angular.io/guide/structural-directives

欢迎交流讨论。

 类似资料: