• 什么是指令,有什么作用?
  • Angular有哪些常用内置指令以及用法?
  • 如何自定义指令并使用?

什么是指令?有什么作用?

  • 指令是为 Angular 应用程序中的元素添加额外行为的类

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

内置指令

属性指令

  • NgClass —— 添加和删除一组 CSS 类。
  • NgStyle —— 添加和删除一组 HTML 样式。

见directives-demo1

  1. /* html*/
  2. <h2>Attribute directives</h2>
  3. <hr><h2 id="ngClass">NgClass Binding</h2>
  4. <div [ngClass]="flagClass?'active':''">NgClass Binding.</div>
  5. <div [ngClass]="currentClasses">NgClass Binding.</div>
  6. <button (click)="setCurrentClass()">change currentClass</button>
  7. <hr><h2 id="ngStyle">NgStyle Binding</h2>
  8. <div [ngStyle]="currentStyle">NgStyle Binding.</div>
  9. <button (click)="setCurrentStyles()">change currentStyles</button>
  10. /* css*/
  11. .active {
  12. color: red
  13. }
  14. /* ts*/
  15. import { Component, Input, Output, EventEmitter } from '@angular/core';
  16. @Component({
  17. selector: 'directives-demo1',
  18. templateUrl: './directives-demo1.component.html',
  19. styleUrls: [ './directives-demo1.component.less' ]
  20. })
  21. export class DirectivesDemo1Component {
  22. flagStyle: boolean = false
  23. flagClass: boolean = false
  24. currentClasses = {}
  25. currentStyle={}
  26. constructor() {
  27. }
  28. setCurrentClass() {
  29. this.flagClass = !this.flagClass
  30. this.currentClasses = {
  31. active: this.flagClass
  32. }
  33. }
  34. setCurrentStyles() {
  35. this.flagStyle = !this.flagStyle
  36. this.currentStyle = {
  37. 'font-size': this.flagStyle ? '24px' : '12px'
  38. }
  39. }
  40. }

结构指令

  • NgIf —— 从模板中创建或销毁子视图。
  • NgFor —— 为列表中的每个条目重复渲染一个节点。
  • NgSwitch —— 一组在备用视图之间切换的指令。
  1. /* html*/
  2. <h2>Structural directives</h2>
  3. <h3 id="ngIf">NgIf Binding</h3>
  4. <div *ngIf="flag">NgIf cool</div>
  5. <div *ngIf="flag;else temp">NgIf cool</div>
  6. <ng-template #temp>NgIf not cool</ng-template>
  7. <button (click)="changeFlag()">change currentClass</button>
  8. <hr><h3 id="ngFor">NgFor Binding</h3>
  9. <div *ngFor="let item of items;let i=index">
  10. name: {{item.name}}&nbsp;&nbsp;&nbsp;&nbsp;index:{{i}}
  11. <hr>
  12. </div>
  13. <!--每个元素只能应用一个结构型指令 -->
  14. <!--<div *ngFor="let item of items;let i=index" *ngIf="item==='A'">
  15. name: {{item.name}}&nbsp;&nbsp;&nbsp;&nbsp;index:{{i}}
  16. <hr>
  17. </div>-->
  18. <!--为没有 DOM 元素的指令安排宿主:Angular <ng-container> 是一个分组元素,它不会干扰样式或布局,因为 Angular 不会将其放置在 DOM 中。-->
  19. <hr><h3>NgFor and NgIf Binding</h3>
  20. <ng-container *ngFor="let item of items;let i=index">
  21. <div *ngIf="i>1">
  22. name: {{item.name}}&nbsp;&nbsp;&nbsp;&nbsp;index:{{i}}
  23. <hr>
  24. </div>
  25. </ng-container>
  26. <!--通过跟踪对条目列表的更改,使用 *ngFor trackBy 属性,Angular 只能更改和重新渲染已更改的条目,而不必重新加载整个条目列表。-->
  27. <hr><h3>NgFor trackBy 跟踪条目</h3>
  28. <div *ngFor="let item of items;let i=index;trackBy:trackByItems">
  29. name: {{item.name}}&nbsp;&nbsp;&nbsp;&nbsp;index:{{i}}
  30. <hr>
  31. </div>
  32. <button (click)="add()">change currentClass</button>
  33. <hr><h3>NgSwitch</h3>
  34. <ng-container *ngFor="let item of items;let i=index">
  35. <div [ngSwitch]="item.name">
  36. <span *ngSwitchCase="'A'"> 我是A</span>
  37. <span *ngSwitchDefault>我是B</span>
  38. </div>
  39. </ng-container>
  40. /* ts*/
  41. import { Component, Input, Output, EventEmitter } from '@angular/core';
  42. @Component({
  43. selector: 'directives-demo1',
  44. templateUrl: './directives-demo2.component.html',
  45. styleUrls: [ './directives-demo2.component.less' ]
  46. })
  47. export class DirectivesDemo2Component {
  48. flag: boolean = false
  49. items = [
  50. { name: 'A', key: 1 },
  51. { name: 'B', key: 2 },
  52. { name: 'C', key: 3 },
  53. { name: 'D', key: 4 }
  54. ]
  55. constructor() {
  56. }
  57. changeFlag() {
  58. this.flag = !this.flag
  59. }
  60. trackByItems(item: any) {
  61. return item.key
  62. }
  63. add() {
  64. this.items = [ { name: 'A', key: 1 },
  65. { name: 'B', key: 2 },
  66. { name: 'C', key: 3 },
  67. { name: 'D', key: 4 },
  68. { name: 'E', key: 5 }
  69. ]
  70. }
  71. }

自定义属性指令

  1. import { Directive, ElementRef, HostListener, Input } from '@angular/core';
  2. /**
  3. * @Directive() 装饰器的配置属性会指定指令的 CSS 属性选择器 [appHighlight]。
  4. * */
  5. @Directive({
  6. selector: '[appHighlight]'
  7. })
  8. export class HighlightDirective {
  9. @Input() appHighlight = '';
  10. @Input() defaultColor = 'yellow';
  11. /**
  12. * ElementRef 的 nativeElement 属性会提供对宿主 DOM 元素的直接访问权限。
  13. * */
  14. constructor(private el: ElementRef) {
  15. //el.nativeElement.style.backgroundColor = 'yellow';
  16. }
  17. private highlight(color: string) {
  18. this.el.nativeElement.style.backgroundColor = color;
  19. }
  20. /**
  21. * 使用 @HostListener() 装饰器,你可以订阅本属性型指令宿主 DOM 元素上的事件
  22. * */
  23. @HostListener('mouseenter') onMouseEnter() {
  24. this.highlight(this.appHighlight||this.defaultColor);
  25. }
  26. @HostListener('mouseleave') onMouseLeave() {
  27. this.highlight('');
  28. }
  29. }

自定义结构指令

  1. /* html*/
  2. <hr><h3>自定义结构指令</h3>
  3. <p *unless="false">unless!!!!</p>
  4. <!--*是一个语法糖等同于,避免复杂写ng-template-->
  5. <ng-template [unless]="false">
  6. <p>unless!!!!</p>
  7. </ng-template>
  8. /* ts*/
  9. import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
  10. /**
  11. * @Directive() 装饰器的配置属性会指定指令的 CSS 属性选择器 [unless]。
  12. * */
  13. @Directive({
  14. selector: '[unless]'
  15. })
  16. export class UnlessDirective {
  17. private hasView = false;
  18. /**
  19. * 通过TemplateRef 拿到宿主的内嵌视图
  20. * 通过ViewContainerRef 拿到宿主视图容器访问权限
  21. * */
  22. constructor(
  23. private templateRef: TemplateRef<any>,
  24. private viewContainer: ViewContainerRef) {
  25. }
  26. @Input() set unless(condition: boolean) {
  27. if (!condition && !this.hasView) {
  28. /**
  29. * 通过createEmbeddedView去实例化视图
  30. * */
  31. this.viewContainer.createEmbeddedView(this.templateRef);
  32. this.hasView = true;
  33. } else if (condition && this.hasView) {
  34. this.viewContainer.clear();
  35. this.hasView = false;
  36. }
  37. }
  38. }