Angular17 Angular自定義指令

1 什麼是HTML

  HTML文檔就是一個純文本文件,該文件包含了HTML元素、CSS樣式以及JavaScript代碼;HTML元素是由標籤呈現,瀏覽器會爲每一個標籤建立帶有屬性的DOM對象,瀏覽器經過渲染這些DOM節點來呈現內容,用戶在瀏覽器中看到的內容就是瀏覽器渲染DOM對象後的結果。node

 

2 指令的分類

  組件、屬性指令、結構性指令瀏覽器

  具體的知識點請參見《Angular2揭祕》app

 

3 指定義指令經常使用到的一些常量

  3.1 Directive

    用於裝飾控制器類來指明該控制器類是一個自定義指令控制器類ide

  3.2 ElementRef

    做爲DOM對象的引用使用,經過構造器進行依賴注入,它的實例表明標註有自定義指令那個元素的DOM對象;每一個標註了自定義指令的元素都會自動擁有一個ElementRef對象來做爲該元素DOM對象的引用(前提:在自定義指令的控制器中依賴注入了ElementRef)this

  3.3 Render2

    Render2的實例是用來操做DOM節點的,由於Angular不推薦直接操做DOM節點;Render2是從Angular4纔開始支持的,以前的版本是使用的Render;每一個標註有自定義指令的元素都會擁有一個Render2實例來操做該元素的DOM屬性(前提:在自定義指令的控制器中依賴注入了Render2)spa

  3.4 HostListener

    用於裝飾事件觸發方法的註解3d

 

4 自定義屬性指令

  一個自定義的屬性指令須要一個有@Directive裝飾器進行裝飾的控制器類code

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

@Directive({
  selector: '[appDirectiveTest02]'
})
export class DirectiveTest02Directive {

  constructor() { }

}

  4.1 實現自定義屬性指令

    4.1.1 建立自定義屬性指令控制類

      技巧01:建立一個模塊來專門放自定義指令orm

ng g d directive/test/directive-test02 --spec=false --module=directive

    4.1.2 在控制器類中依賴注入ElementRef  

  constructor(
    private el: ElementRef
  ) {}

    4.1.3 經過ElementRef實例改變標有自定義指令元素對應的DOM對象的背景顏色 

  ngOnInit() {
    this.el.nativeElement.style.backgroundColor = 'skyblue';
  }

    4.1.3 在自定義指令模塊中指定exports

      

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DirectiveTest01Directive } from './test/directive-test01.directive';
import { SharedModule } from '../shared/shared.module';
import { DirectiveTest02Directive } from './test/directive-test02.directive';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    DirectiveTest01Directive,
    DirectiveTest02Directive],
  exports: [
    DirectiveTest01Directive,
    DirectiveTest02Directive
  ]
})
  
export class DirectiveModule { }
View Code

    4.1.4 將自定義指令模塊導入到須要用到指定指令的組件所在的模塊中

      技巧01:自定義指令通常會被屢次用到,因此通常會將自定義指令模塊導入到共享模塊在從共享模塊導出,這樣其它模塊只須要導入共享模塊就能夠啦router

      

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { 
  MdToolbarModule,
  MdSidenavModule,
  MdIconModule,
  MdButtonModule,
  MdCardModule,
  MdInputModule,
  MdRadioModule,
  MdRadioButton
 } from '@angular/material';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { DirectiveModule } from '../directive/directive.module'; 

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    MdToolbarModule,
    MdSidenavModule,
    MdIconModule,
    MdButtonModule,
    MdCardModule,
    MdInputModule,
    DirectiveModule,
    MdRadioModule
  ],
  declarations: [],
  exports: [
    CommonModule,
    RouterModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    MdToolbarModule,
    MdSidenavModule,
    MdIconModule,
    MdButtonModule,
    MdCardModule,
    MdInputModule,
    DirectiveModule,
    MdRadioButton
  ]
})
export class SharedModule { }
View Code

    4.1.5 在組件中使用自定組件對應的選擇器便可

      自定義指令的選擇器是由@Directive裝飾器的selector元數據指定的

        

      在元素中直接標註自定義指令的選擇器就行啦

       

<div class="panel panel-primary">
    <div class="panel panel-heading">實現自定義屬性指令</div>
    <div class="panel-body">
        <button md-raised-button appDirectiveTest02>實現自定義指令的按鈕</button>
        <br /><br />
        <button md-raised-button>未實現自定以指令的按鈕</button>
    </div>
    <div class="panel-footer">2018-1-20 22:47:06</div>
</div>
View Code

    4.1.6 代碼彙總

import { Directive, ElementRef } from '@angular/core';
import { OnInit } from '../../../../node_modules/_@angular_core@4.4.6@@angular/core/src/metadata/lifecycle_hooks';

@Directive({
  selector: '[appDirectiveTest02]'
})
export class DirectiveTest02Directive implements OnInit {

  constructor(
    private el: ElementRef
  ) {}

  ngOnInit() {
    this.el.nativeElement.style.backgroundColor = 'skyblue';
  }

}

  4.2 給自定義屬性指令綁定輸入屬性

    在4.1中實現的自定義屬性指令中背景顏色是寫死的不能更改,咱們能夠給指令綁定輸入屬性實現數據傳遞,從而達到動態改變的目的

    4.2.1 在自定義屬性指令的控制器中添加一個輸入屬性myColor

      

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

@Directive({
  selector: '[appDirectiveTest02]'
})
export class DirectiveTest02Directive implements OnInit {

  @Input()
  myColor: string;

  constructor(
    private el: ElementRef
  ) {}

  ngOnInit() {
    this.el.nativeElement.style.backgroundColor = this.myColor;
  }

}
View Code

    4.2.2 在組件中給myColor屬性賦值

      技巧01:在給輸入屬性賦值時,等號右邊若是不是一個變量就須要用單引號括起來

      

<div class="panel panel-primary">
    <div class="panel panel-heading">實現自定義屬性指令</div>
    <div class="panel-body">
        <button md-raised-button appDirectiveTest02 [myColor]="'red'">實現自定義指令的按鈕</button>
        <br /><br />
        <button md-raised-button>未實現自定以指令的按鈕</button>
    </div>
    <div class="panel-footer">2018-1-20 22:47:06</div>
</div>
View Code

    4.2.3 效果展現

      

    4.2.4 改進

      能夠經過自定義屬性指令的選擇器來實現數據傳輸

      》利用自定義屬性指令的選擇器做爲輸入屬性myColor輸入屬性的別名

        

      》在組件中直接利用自定義指令的選擇器做爲輸入屬性

        

<div class="panel panel-primary">
    <div class="panel panel-heading">實現自定義屬性指令</div>
    <div class="panel-body">
        <button md-raised-button [appDirectiveTest02]="'yellow'">實現自定義指令的按鈕</button>
        <br /><br />
        <button md-raised-button>未實現自定以指令的按鈕</button>
    </div>
    <div class="panel-footer">2018-1-20 22:47:06</div>
</div>
View Code

      》 效果展現

        

  4.3 響應用戶操做

    在自定義屬性指令中經過監聽DOM對象事件來進行一些操做

    4.2.1 引入 HostListener 註解並編寫一個方法    

      技巧01:HostListener註解能夠傳入兩個參數

        參數1 -> 須要監聽的事件名稱

        參數2 -> 事件觸發時傳遞的方法

  @HostListener('click', ['$event'])
  onClick(ev: Event) {
     
  }

    4.2.2 在方法中實現一些操做

  @HostListener('click', ['$event'])
  onClick(ev: Event) {
    if (this.el.nativeElement === ev.target) {
      if (this.el.nativeElement.style.backgroundColor === 'green') {
        this.el.nativeElement.style.backgroundColor = 'skyblue';
      } else {
        this.el.nativeElement.style.backgroundColor = 'green';
      }
    }
    // if (this.el.nativeElement.style.backgroundColor === 'yellow') {
    //   this.el.nativeElement.style.backgroundColor = 'green';
    // } else {
    //   this.el.nativeElement.style.backgroundColor = 'yellow';
    // }
  }

    4.2.3 在組件中標記自定義屬性指令的選擇器就能夠啦

      

<div class="panel panel-primary">
    <div class="panel panel-heading">實現自定義屬性指令</div>
    <div class="panel-body">
        <button md-raised-button appDirectiveTest02 >實現自定義指令的按鈕</button>
        <br /><br />
        <button md-raised-button>未實現自定以指令的按鈕</button>
    </div>
    <div class="panel-footer">2018-1-20 22:47:06</div>
</div>
 
View Code

    4.2.4 代碼彙總

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

@Directive({
  selector: '[appDirectiveTest02]'
})
export class DirectiveTest02Directive implements OnInit {

  constructor(
    private el: ElementRef
  ) {}

  ngOnInit() {
  }

  @HostListener('click', ['$event'])
  onClick(ev: Event) {
    if (this.el.nativeElement === ev.target) {
      if (this.el.nativeElement.style.backgroundColor === 'green') {
        this.el.nativeElement.style.backgroundColor = 'skyblue';
      } else {
        this.el.nativeElement.style.backgroundColor = 'green';
      }
    }
    // if (this.el.nativeElement.style.backgroundColor === 'yellow') {
    //   this.el.nativeElement.style.backgroundColor = 'green';
    // } else {
    //   this.el.nativeElement.style.backgroundColor = 'yellow';
    // }
  }

}
View Code

   4.4 自定義拖拽屬性指令

    效果預演:拖拽一個標註有自定義屬性指令的元素時,該元素會自動添加一個紅色的邊框;當拖拽結束時該邊框會自動結束

    4.4.1 添加輸入屬性

      在自定義屬性指令控制器的選擇器上添加一個選擇器做爲一個輸入屬性的別名,在控制器類中定義一個輸入屬性,並且保持這個輸入屬性的名稱和選擇器中心添加的那個選擇器一致(目的是爲了減小@Input註解使用別名),固然保持一致時也能夠,那就必須在輸入屬性的@Input註解上添加一個和新添加的選擇器一致的名稱

      

      輸入屬性使用別名的寫法

        

 

    4.4.2 在組件中使用指令選擇器和屬性選擇器

      

       使用別名的寫法

        

    4.4.3 效果演示

      

    4.4.4 代碼彙總

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

@Directive({
  selector: '[appDirectiveTest02][myDraggedClass]'
})
export class DirectiveTest02Directive implements OnInit {

  @Input('myDraggedClass')
  draggedClass: string;

  /**
   * 把自定義指令做爲一個輸入屬性的別名,這裏將@Input放在set方法之上是爲了經過一個輸入屬性實現多種控制
   * 利用Render2對象實例能夠對DOM對象的屬性進行操做
   */
  private _isDraggable = false;
  @Input('appDirectiveTest02')
  set isDraggable(value: boolean) {
    this._isDraggable = value;
    this.rd.setAttribute(this.el.nativeElement, 'draggable', `${value}`);
  }

  constructor(
    private el: ElementRef,
    private rd: Renderer2
  ) {}

  ngOnInit() {
  }

  /**
   * 監聽拖拽的開始
   * @param ev 拖拽開始事件對象
   */
  @HostListener('dragstart', ['$event'])
  onDragStart(ev: Event) {
    /**
     * 若是觸發拖拽事件的對象是標註有自定義屬性指令的對象,那麼就對該DOM對象進行一些屬性操做
     */
    if (this.el.nativeElement === ev.target) {
      this.rd.addClass(this.el.nativeElement, this.draggedClass);
    }
  }

  /**
   * 監聽拖拽的結束
   * @param ev 拖拽結束事件對象
   */
  @HostListener('dragend', ['$event'])
  onDragEnd(ev: Event) {
    if (this.el.nativeElement === ev.target) {
      this.rd.removeClass(this.el.nativeElement, this.draggedClass);
    }
  }

}
自定義拖拽指令控制類
<div class="panel panel-primary">
    <div class="panel panel-heading">實現自定義拖拽屬性指令</div>
    <div class="panel-body">
        <button md-raised-button [appDirectiveTest02]="true" [myDraggedClass]="'drag'" >實現自定義指令的按鈕</button>
        <br /><br />
        <button md-raised-button>未實現自定以指令的按鈕</button>
    </div>
    <div class="panel-footer">2018-1-20 22:47:06</div>
</div>
HTML
.drag {
    border: red solid 2px;
}
View Code
相關文章
相關標籤/搜索