【angular】@Directive

Angular中有三种类型的指令directive

组件@Component — 拥有模板的指令,我们在另外一文已专门学习过啦。本文就不涉及改指令的内容了。

结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令。例如,*NgFor*NgIf。你可能注意到了指令名的星号*前缀,它是一个语法糖, 从内部实现来说,Angular*... 属性 翻译成一个 元素 并用它来包裹宿主元素,代码如下:

{{hero.name}}
{{hero.name}}
({{i}}) {{hero.name}}
({{i}}) {{hero.name}}

属性型指令 — 改变元素、组件或其它指令的外观和行为的指令。例如,内置的 NgStyle 指令可以同时修改元素的多个样式

A. 属性型指令

属性型指令至少需要一个带有 @Directive 装饰器的控制器类。该装饰器指定了一个用于标识属性的选择器。 控制器类实现了指令需要的指令行为。本节展示了如何创建一个简单的属性型指令 appHighlight,当用户把鼠标悬停在一个元素上时,改变它的背景色。你可以这样用它:


Highlight me!

指令名为啥不直接叫做 highlight
① 尽管 highlight是一个比 appHighlight 更简洁的名字,而且它确实也能工作。 但是最佳实践是在选择器名字前面添加前缀,以确保它们不会与标准 HTML 属性冲突。 它同时减少了与第三方指令名字发生冲突的危险。
② 确认你没有highlight 指令添加ng前缀。 那个前缀属于 Angular,使用它可能导致难以诊断的 bug

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

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

ElementRef :注入宿主 DOM 元素的引用,也就是你放置 appHighlight 的那个元素。它通过其 nativeElement 属性给你了直接访问宿主 DOM 元素的能力。

当前,appHighlight 只是简单的设置元素的颜色。 这个指令应该在用户鼠标悬浮一个元素时,设置它的颜色。

HostListener(这个我们在@Component一文中也略有提到)加进导入列表中

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

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

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

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

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

运行本应用并确认:当把鼠标移到 p 上的时候,背景色就出现了,而移开时就消失了

image

使用 @Input 数据绑定向指令传递值

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

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

  constructor(private el: ElementRef) { }

  @Input('appHighlight') highlightColor: string;

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

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

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

测试案例:

My First Attribute Directive

Pick a highlight color

Green Yellow Cyan

Highlight me!

image

B. 结构型指令

有时你会希望只有当特定的条件为真时才重复渲染一个 HTML 块。 但 Angular 不允许。这是因为你在一个元素上只能放一个结构型指令。

结构型指令可能会对宿主元素及其子元素做很复杂的事。当两个指令放在同一个元素上时,谁先谁后?NgIf优先还是 NgFor 优先?NgIf 可以取消 NgFor 的效果吗? 如果要这样做,Angular 应该如何把这种能力泛化,以取消其它结构型指令的效果呢?

在文章开头我们已经介绍了*ngIf*ngFor

再来具体解析下*ngFor

  • let 关键字声明一个模板输入变量,你会在模板中引用它。本例子中,这个输入变量就是 heroiodd。 解析器会把 let herolet ilet odd 翻译成命名变量 let-herolet-ilet-odd
  • 微语法解析器接收 oftrackby,把它们首字母大写(of -> Of, trackBy -> TrackBy), 并且给它们加上指令的属性名(ngFor)前缀,最终生成的名字是 ngForOfngForTrackBy。 这两个最终生成的名字是 NgFor输入属性,指令据此了解到列表是 heroes,而 track-by 函数是 trackById
  • API 参考手册中描述了 NgFor 指令的其它属性和上下文属性。

NgSwitch了解下
AngularNgSwitch实际上是一组相互合作的指令:NgSwitchNgSwitchCaseNgSwitchDefault


C. ng-template & ng-container

元素:是一个 Angular 元素,用来渲染 HTML它永远不会直接显示出来。 事实上,在渲染视图之前,Angular 会把 及其内容替换为一个注释。

如果没有使用结构型指令,而仅仅把一些别的元素包装进 中,那些元素就是不可见的。结构型指令会让 正常工作

的救赎:类似ReactFragments
还有一个问题是:有些 HTML 元素需要所有的直属下级都具有特定的类型。 比如,show sad)

上述代码的效果:下拉列表就是空的


Angular 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。 是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScriptif 块中的花括号

Pick your favorite hero ()

下拉框工作正常


image

自定义结构型指令

在本节中,你会写一个名叫 UnlessDirective 的结构型指令,它是 NgIf 的反义词

import { Directive, Input, TemplateRef, ViewContainerRef } 
  from '@angular/core';

/**
 * Add the template content to the DOM unless the condition is true.
 */
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
  private hasView = false;

  constructor(
    private templateRef: TemplateRef,
    private viewContainer: ViewContainerRef) { }

  //没有人会读取 appUnless 属性,因此它不需要定义 getter
  @Input() set appUnless(condition: boolean) {
    if (!condition && !this.hasView) {
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (condition && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false;
    }
  }
}

把这个指令添加到 AppModuledeclarations 数组中。然后创建一些 HTML 来试用一下。

(A) This paragraph is displayed because the condition is false.

(B) Although the condition is true, this paragraph is displayed because appUnless is set to false.


Angular有哪些内置指令?

等本人学习了解后再来补充吧...

你可能感兴趣的:(【angular】@Directive)