3

我们之前并没有接触过指令,但是可能对这个词并不陌生,例如我们经常会看到这样的编译器报错:
图片.png
那么我们由此也可以大致猜测出指令是在那里使用的了。

要想进一步了解指令就需要去官方文档中去了解了。

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

@Directive({
  selector: '[appCheckSingle]'
})
export class CheckSingleDirective {}

首先就是如何在组件中使用指令,也就是我们所熟悉的selector,这里的selector规则与组件不同,组件在使用是是直接作为标签来使用如:

<app-xxxSelect></app-xxxSelect>

而指令是作为标签的属性来使用的,也就是说上面的指令要这样来声明此标签用到了这个指令。

  <div appCheckSingle></div>

在官方文档中我们还可以了解到我们还可以靠selector来设置让哪些标签可以调用该指令。比如我们只想让类型为输入框的input标签调用此指令:

@Directive({
  selector: 'input[type=text]'
})
export class CheckSingleDirective implements OnInit, OnDestroy {
.  .  .
  @Input()
  appCheckSingle = {} as {id: number};
.  .  .

}

图片.png

但是上述功能虽然可以正常实现但是编译器会发生报错:

ESLint: The selector should start with one of these prefixes: &quot;app&quot; (https://angular.io/guide/styleguide#style-02-08) (@angular-eslint/directive-selector)

说我们前缀不符合要求,这是由于在angular配置文件中规定了其默认格式,将下述代码中"prefix": "app",注释掉就不会发生报错,可能是angular在版本更新中忽视了此点或是默认情况下不允许这么操作?

配置文件.eslintrc.json中有其默认格式:

"@angular-eslint/directive-selector": [
          "error",
          {
            "type": "attribute",
            "prefix": "app",
            "style": "camelCase"
          }
        ]

1、需要是属性
2、以app为前缀
3、命名格式为小驼峰

我们在官方文档中还可以得知指令和组件一样也有着生命周期,也可以通过@input、@outPut来和组件进行数据的传递。

那么如果一个组件中加入了多个指令那么这多个指令间可以直接进行互动吗?
答案是可以,可以通过exportAs来将此指令抛出。

@Directive({
  selector: '[appCheckAll]',
  exportAs: 'appCheckAll'
})

我们在使用时像下面这样即可:
图片.png

下面来介绍一下如何用指令实现单选和全选:
图片.png
首先就是如何传入选项信息,这里和之前靠组件实现单全选组件的方式不同,并不需要对前台实体加入是否被选择属性,直接传入所需选项即可。

也就是说我们在组件中只需准备这些数据即可:

  public items = [{id: 2}, {id: 1}, {id: 3}, {id: 4}] as {id: number}[];
  public selectedItems = [];
<div>
  <label><input type="checkbox" [appCheckAll]="items"
          [checkedItems]="selectedItems"
          #checkAll="appCheckAll"/>全选</label>
</div>
<div *ngFor="let item of items">
  <label><input type="checkbox" [appCheckSingle]="item"
                [checkAllDirective]="checkAll"/>
                单选
  </label>
</div>

由于这并不是组件而是指令所以只要将selectedItems传入就可以在指令里进行相应操作就可以反馈到组件中,并不需要像子组件向父组件那样进行弹值。就像formcontrol与input标签进行绑定时所输入的信息可以直接传入formcontrol中那样。

然后我们要做的就是怎么在指令中获取所绑定标签的的选择情况用于初始化,比如怎么得知指令对应的选择框是否被选中。这时候就需要获取宿主(即绑定的标签)。

  /**
   * 宿主
   */
  checkboxElement: HTMLInputElement;

  constructor(private elementRef: ElementRef<HTMLElement>) {
    this.checkboxElement = elementRef.nativeElement as HTMLInputElement;
  }

图片.png
其中就包含了选择框的选择信息图片.png
然后就是要获取实时的互动信息,虽然我们知道了初始情况下的选择情况,但是当宿主信息有变化时我们怎么获取呢。
angular还给我们提供了可以侦听DOM事件的装饰器。

@HostListener('click')
  onClick()

比如像这样声明就可以在宿主发出click事件时调用指令中的onClick方法。

如果想要在单选指令中获取多选指令信息或是控制多选靠多选指令exportAs进行引用即可。

由于多选指令可以直接由exportAs传递给单选指令才使得单选指令也可以对selectedItems进行处理,可以订阅多选组件的弹射器来获取其弹射的内容。

只后我们的逻辑就如下图所示:
未命名文件(8).png

经过此次对指令的使用又获得了一种新的处理问题的方法,对于类似选择框的问题可以不借助于修改前台实体来进行传递值。相对于组件来说更加灵活,也更便于使用和书写(因为指令只需要一个ts文件即可)。


李明
441 声望18 粉丝