【angular】@Directive

Angular中有三種類型的指令directive

組件@Component — 擁有模板的指令,我們?cè)诹硗庖晃囊褜iT學(xué)習(xí)過啦虽惭。本文就不涉及改指令的內(nèi)容了耘眨。

結(jié)構(gòu)型指令 — 通過添加和移除 DOM 元素改變 DOM 布局的指令浮还。例如,*NgFor*NgIf。你可能注意到了指令名的星號(hào)*前綴滨攻,它是一個(gè)語法糖, 從內(nèi)部實(shí)現(xiàn)來說蓝翰,Angular*... 屬性 翻譯成一個(gè) <ng-template> 元素 并用它來包裹宿主元素光绕,代碼如下:

<div *ngIf="hero" class="name">{{hero.name}}</div>

<ng-template [ngIf]="hero"> 
  <div  class="name">{{hero.name}}</div>  
</ng-template>

<!-- ------------------------------ -->

<div *ngFor="let hero of heroes; let i=index; 
    let odd=odd; trackBy: trackById" 
  [class.odd]="odd">
  ({{i}}) {{hero.name}}
</div>

<ng-template ngFor 
  let-hero [ngForOf]="heroes" let-i="index" 
  let-odd="odd" [ngForTrackBy]="trackById">
  <div [class.odd]="odd">
    ({{i}}) {{hero.name}}
  </div>
</ng-template>

屬性型指令 — 改變?cè)亍⒔M件或其它指令的外觀和行為的指令畜份。例如诞帐,內(nèi)置的 NgStyle 指令可以同時(shí)修改元素的多個(gè)樣式

A. 屬性型指令

屬性型指令至少需要一個(gè)帶有 @Directive 裝飾器的控制器類。該裝飾器指定了一個(gè)用于標(biāo)識(shí)屬性的選擇器爆雹。 控制器類實(shí)現(xiàn)了指令需要的指令行為停蕉。本節(jié)展示了如何創(chuàng)建一個(gè)簡單的屬性型指令 appHighlight愕鼓,當(dāng)用戶把鼠標(biāo)懸停在一個(gè)元素上時(shí),改變它的背景色慧起。你可以這樣用它:

<!-- 使用屬性型指令 -->
<p appHighlight>Highlight me!</p>

指令名為啥不直接叫做 highlight菇晃?
① 盡管 highlight是一個(gè)比 appHighlight 更簡潔的名字,而且它確實(shí)也能工作蚓挤。 但是最佳實(shí)踐是在選擇器名字前面添加前綴磺送,以確保它們不會(huì)與標(biāo)準(zhǔn) HTML 屬性沖突。 它同時(shí)減少了與第三方指令名字發(fā)生沖突的危險(xiǎn)屈尼。
② 確認(rèn)你沒有highlight 指令添加ng前綴册着。 那個(gè)前綴屬于 Angular,使用它可能導(dǎo)致難以診斷的 bug

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

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

ElementRef注入宿主 DOM 元素的引用脾歧,也就是你放置 appHighlight 的那個(gè)元素甲捏。它通過其 nativeElement 屬性給你了直接訪問宿主 DOM 元素的能力。

當(dāng)前鞭执,appHighlight 只是簡單的設(shè)置元素的顏色司顿。 這個(gè)指令應(yīng)該在用戶鼠標(biāo)懸浮一個(gè)元素時(shí),設(shè)置它的顏色兄纺。

HostListener(這個(gè)我們?cè)?code>@Component一文中也略有提到)加進(jìn)導(dǎo)入列表中

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;
  }
}

運(yùn)行本應(yīng)用并確認(rèn):當(dāng)把鼠標(biāo)移到 p 上的時(shí)候大溜,背景色就出現(xiàn)了,而移開時(shí)就消失了

image

使用 @Input 數(shù)據(jù)綁定向指令傳遞值

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;
  }
}

測(cè)試案例:

<h1>My First Attribute Directive</h1>

<h4>Pick a highlight color</h4>
<div>
  <input type="radio" name="colors" (click)="color='lightgreen'">Green
  <input type="radio" name="colors" (click)="color='yellow'">Yellow
  <input type="radio" name="colors" (click)="color='cyan'">Cyan
</div>
<p [appHighlight]="color">Highlight me!</p>
image

B. 結(jié)構(gòu)型指令

有時(shí)你會(huì)希望只有當(dāng)特定的條件為真時(shí)才重復(fù)渲染一個(gè) HTML 塊估脆。 但 Angular 不允許钦奋。這是因?yàn)槟阍谝粋€(gè)元素上只能放一個(gè)結(jié)構(gòu)型指令。

結(jié)構(gòu)型指令可能會(huì)對(duì)宿主元素及其子元素做很復(fù)雜的事疙赠。當(dāng)兩個(gè)指令放在同一個(gè)元素上時(shí)付材,誰先誰后?NgIf優(yōu)先還是 NgFor 優(yōu)先圃阳?NgIf 可以取消 NgFor 的效果嗎厌衔? 如果要這樣做,Angular 應(yīng)該如何把這種能力泛化捍岳,以取消其它結(jié)構(gòu)型指令的效果呢富寿?

在文章開頭我們已經(jīng)介紹了*ngIf*ngFor

再來具體解析下*ngFor

  • let 關(guān)鍵字聲明一個(gè)模板輸入變量,你會(huì)在模板中引用它锣夹。本例子中页徐,這個(gè)輸入變量就是 heroiodd银萍。 解析器會(huì)把 let hero泞坦、let ilet odd 翻譯成命名變量 let-herolet-ilet-odd砖顷。
  • 微語法解析器接收 oftrackby贰锁,把它們首字母大寫(of -> Of, trackBy -> TrackBy)赃梧, 并且給它們加上指令的屬性名(ngFor)前綴,最終生成的名字是 ngForOfngForTrackBy豌熄。 這兩個(gè)最終生成的名字是 NgFor輸入屬性授嘀,指令據(jù)此了解到列表是 heroes,而 track-by 函數(shù)是 trackById锣险。
  • API 參考手冊(cè)中描述了 NgFor 指令的其它屬性和上下文屬性蹄皱。

NgSwitch了解下
AngularNgSwitch實(shí)際上是一組相互合作的指令:NgSwitchNgSwitchCaseNgSwitchDefault芯肤。

<div [ngSwitch]="hero?.emotion">
  <app-happy-hero    *ngSwitchCase="'happy'"  [hero]="hero">
  </app-happy-hero>
  <app-sad-hero      *ngSwitchCase="'sad'"  [hero]="hero">
  </app-sad-hero>
  <app-confused-hero *ngSwitchCase="'confused'" [hero]="hero">
  </app-confused-hero>
  <app-unknown-hero  *ngSwitchDefault  [hero]="hero">
  </app-unknown-hero>
</div>

<div [ngSwitch]="hero?.emotion">
  <ng-template [ngSwitchCase]="'happy'">
    <app-happy-hero [hero]="hero"></app-happy-hero>
  </ng-template>
  <ng-template [ngSwitchCase]="'sad'">
    <app-sad-hero [hero]="hero"></app-sad-hero>
  </ng-template>
  <ng-template [ngSwitchCase]="'confused'">
    <app-confused-hero [hero]="hero"></app-confused-hero>
  </ng-template >
  <ng-template ngSwitchDefault>
    <app-unknown-hero [hero]="hero"></app-unknown-hero>
  </ng-template>
</div>

C. ng-template & ng-container

<ng-template>元素:是一個(gè) Angular 元素巷折,用來渲染 HTML它永遠(yuǎn)不會(huì)直接顯示出來崖咨。 事實(shí)上锻拘,在渲染視圖之前,Angular 會(huì)把 <ng-template> 及其內(nèi)容替換為一個(gè)注釋击蹲。

如果沒有使用結(jié)構(gòu)型指令署拟,而僅僅把一些別的元素包裝進(jìn) <ng-template> 中,那些元素就是不可見的歌豺。結(jié)構(gòu)型指令會(huì)讓 <ng-template> 正常工作

<ng-container> 的救贖:類似ReactFragments
還有一個(gè)問題是:有些 HTML 元素需要所有的直屬下級(jí)都具有特定的類型推穷。 比如,<select> 元素要求直屬下級(jí)必須為 <option>类咧,那就沒辦法把這些選項(xiàng)包裝進(jìn) <div><span> 中馒铃。如:

<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked 
    (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <span *ngFor="let h of heroes">
    <span *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </span>
  </span>
</select>

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


Angular<ng-container> 是一個(gè)分組元素,但它不會(huì)污染樣式或元素布局痕惋,因?yàn)?Angular 壓根不會(huì)把它放進(jìn) DOM 中骗露。<ng-container> 是一個(gè)由 Angular 解析器負(fù)責(zé)識(shí)別處理的語法元素。 它不是一個(gè)指令血巍、組件、類或接口珊随,更像是 JavaScriptif 塊中的花括號(hào)

<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked 
    (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <ng-container *ngFor="let h of heroes">
    <ng-container *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </ng-container>
  </ng-container>
</select>

下拉框工作正常


image

自定義結(jié)構(gòu)型指令

在本節(jié)中述寡,你會(huì)寫一個(gè)名叫 UnlessDirective 的結(jié)構(gòu)型指令,它是 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<any>,
    private viewContainer: ViewContainerRef) { }

  //沒有人會(huì)讀取 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;
    }
  }
}

把這個(gè)指令添加到 AppModuledeclarations 數(shù)組中鲫凶。然后創(chuàng)建一些 HTML 來試用一下。

<p *appUnless="condition" class="unless a">
  (A) This paragraph is displayed because the condition is false.
</p>

<p *appUnless="!condition" class="unless b">
  (B) Although the condition is true,
  this paragraph is displayed because appUnless is set to false.
</p>

Angular有哪些內(nèi)置指令?

等本人學(xué)習(xí)了解后再來補(bǔ)充吧...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衩辟,一起剝皮案震驚了整個(gè)濱河市螟炫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艺晴,老刑警劉巖昼钻,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掸屡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡然评,警方通過查閱死者的電腦和手機(jī)仅财,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碗淌,“玉大人盏求,你說我怎么就攤上這事∫诿撸” “怎么了碎罚?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纳像。 經(jīng)常有香客問我荆烈,道長,這世上最難降的妖魔是什么爹耗? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任耙考,我火速辦了婚禮,結(jié)果婚禮上潭兽,老公的妹妹穿的比我還像新娘倦始。我一直安慰自己,他們只是感情好山卦,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布鞋邑。 她就那樣靜靜地躺著,像睡著了一般账蓉。 火紅的嫁衣襯著肌膚如雪枚碗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天铸本,我揣著相機(jī)與錄音肮雨,去河邊找鬼。 笑死箱玷,一個(gè)胖子當(dāng)著我的面吹牛怨规,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锡足,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼波丰,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了舶得?” 一聲冷哼從身側(cè)響起掰烟,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后纫骑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝎亚,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年惧磺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颖对。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡磨隘,死狀恐怖缤底,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情番捂,我是刑警寧澤个唧,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站设预,受9級(jí)特大地震影響徙歼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳖枕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一魄梯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宾符,春花似錦酿秸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哄褒,卻和暖如春稀蟋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呐赡。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工退客, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人链嘀。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓萌狂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親管闷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容