HTML文檔就是一個純文本文件,該文件包含了HTML元素、CSS樣式以及JavaScript代碼;HTML元素是由標籤呈現,瀏覽器會爲每一個標籤建立帶有屬性的DOM對象,瀏覽器經過渲染這些DOM節點來呈現內容,用戶在瀏覽器中看到的內容就是瀏覽器渲染DOM對象後的結果。node
組件、屬性指令、結構性指令瀏覽器
具體的知識點請參見《Angular2揭祕》app
用於裝飾控制器類來指明該控制器類是一個自定義指令控制器類ide
做爲DOM對象的引用使用,經過構造器進行依賴注入,它的實例表明標註有自定義指令那個元素的DOM對象;每一個標註了自定義指令的元素都會自動擁有一個ElementRef對象來做爲該元素DOM對象的引用(前提:在自定義指令的控制器中依賴注入了ElementRef)this
Render2的實例是用來操做DOM節點的,由於Angular不推薦直接操做DOM節點;Render2是從Angular4纔開始支持的,以前的版本是使用的Render;每一個標註有自定義指令的元素都會擁有一個Render2實例來操做該元素的DOM屬性(前提:在自定義指令的控制器中依賴注入了Render2)spa
用於裝飾事件觸發方法的註解3d
一個自定義的屬性指令須要一個有@Directive裝飾器進行裝飾的控制器類code
import { Directive } from '@angular/core'; @Directive({ selector: '[appDirectiveTest02]' }) export class DirectiveTest02Directive { constructor() { } }
技巧01:建立一個模塊來專門放自定義指令orm
ng g d directive/test/directive-test02 --spec=false --module=directive
constructor(
private el: ElementRef
) {}
ngOnInit() { this.el.nativeElement.style.backgroundColor = 'skyblue'; }
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 { }
技巧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 { }
自定義指令的選擇器是由@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>
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.1中實現的自定義屬性指令中背景顏色是寫死的不能更改,咱們能夠給指令綁定輸入屬性實現數據傳遞,從而達到動態改變的目的
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; } }
技巧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>
能夠經過自定義屬性指令的選擇器來實現數據傳輸
》利用自定義屬性指令的選擇器做爲輸入屬性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>
》 效果展現
在自定義屬性指令中經過監聽DOM對象事件來進行一些操做
技巧01:HostListener註解能夠傳入兩個參數
參數1 -> 須要監聽的事件名稱
參數2 -> 事件觸發時傳遞的方法
@HostListener('click', ['$event'])
onClick(ev: Event) {
}
@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'; // } }
<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>
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'; // } } }
效果預演:拖拽一個標註有自定義屬性指令的元素時,該元素會自動添加一個紅色的邊框;當拖拽結束時該邊框會自動結束
在自定義屬性指令控制器的選擇器上添加一個選擇器做爲一個輸入屬性的別名,在控制器類中定義一個輸入屬性,並且保持這個輸入屬性的名稱和選擇器中心添加的那個選擇器一致(目的是爲了減小@Input註解使用別名),固然保持一致時也能夠,那就必須在輸入屬性的@Input註解上添加一個和新添加的選擇器一致的名稱
輸入屬性使用別名的寫法
使用別名的寫法
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>
.drag { border: red solid 2px; }