1 什么是模板
它是頁面呈現的骨架,是盛裝組件數據的容器。與之相關的內容包括了-----模板與組件件 '數據交互'、'內置指令'、'表單'、'管道'等。
1.1 模板語法概覽
//插值:綁定屬性變量的值到模板中 //插值:綁定屬性變 <p>{{ detail.telNum }}</p> //DOM元素屬性綁定:將模板表達式name的值綁定到元素<div>的屬性title上 <div [title]="name"></div> //HTML標簽特性綁定:將模板表達式的返回值綁定到元素<td>標簽特性colspan上 <td [attr.colspan]="{{ 1+2 }}">合並單元格</td> //Class類綁定:當isBlue()函數值為true時為div添加類名為isBlue的樣式 <div [class.isblue]="isBlue()"></div> //Style樣式綁定:當表達式isRed的值為為true時設置button的文字顏色為紅色,否則為綠色 <button [style.color]="isRed ? 'red':'green'">紅色</button> //事件綁定:單擊元素時會觸發click事件,需要時也可以傳遞$event對象,如(click)="editContact($event)" <a class='edit' (click)="editContact()"></a> //雙向綁定:組件和模板間雙向數據綁定,等價於<div [title]="name" (titleChange)="name=$event"></div> <div [(title)]="name"></div> //模板局部變量:在當前模板中創建一個對id值為name的input元素的引用變量name,相當於document.getElementById("name") <input type='text' ##name name="name" id="name"/> //管道操作符:原始數據birthday經管道轉換后輸出期望數據並顯示在模板中 <p>張三的生日是{{ birthday | date }}</p> //模板表達式操作符:模板表達式操作符表明detail.telNum屬性不是必須存在的,如果它的值是undefined,那么后面的表達式將會被忽略,不會引發異常 <p>{{ detail?.telNum }}</p> //星號前綴:使用星號前綴可以簡化對結構指令的使用,Angular會將帶有星號的指令引用替換成帶有<template>標簽的代碼, //等價於<template [myUnless]="boolValue"><p>myUnless is false now.</p></template> <p *myUnless="boolValue">myUnless is false now.</p>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
2 數據綁定
根據數據流向可以分為三種:
- 單向:數據源到視圖
//插值DOM元素屬性 <p>{{ detail.telNum }}</P> //綁定HTML標簽特性 <div [title]="name"></div> //綁定 <div [style.color]="color">hello world</div>
- 單向:從視圖目標到數據源
//事件綁定 (click)="editContact()" on-click="editContact()"
- 雙向
//雙向綁定
<div [(title)]="name"></div> <div bindon-title="name"></div>
- 1
- 2
- 3
NOTE
Property為DOM對象屬性,以DOM元素作為多想,其附加內容,是在文檔對象模型里定義的,如childNodes、firstChild。 而Attribute為HTML標簽特性,是DOM節點自帶的屬性,在HTML中定義的,即只要是在HTML標簽中出現的屬性(HTML代碼)都是Attribute。
數據綁定是借助於DOM對象屬性和事件來運作的。
2.1 插值
雙大括號{{ }}語法來實現。
2.2 模板表達式
類似於JS的表達式,絕大多數JS表達式均為合法模板表達式。它應用於插值語法雙大括號中和屬性綁定“=”右側的括號中。但以下JS表達式不是合法模板表達式:
- 帶有new運算符的表達式
- 賦值表達式
- 帶有 ; 或者 , 的鏈式表達式
- 帶有自增自減
模板表達式不支持位運算。
2.3 屬性綁定
DOM元素屬性綁定:把DOM對象屬性綁定到組件的屬性上,而綁定目標可以是中括號,也可以加前綴,還可以使用屬性綁定設置自定義組件的輸入屬性。
//中括號 <div [title]="titleText"></div> //加前綴 <div bind-title="titleText"></div> //自定義組件的輸入屬性 <user-detail [user]="currentUser"></user-detail>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
NOTE:
中括號的作用是計算右側模板表達式,如果沒有中括號,右側表達式會被當成字符串常量,如果是字符串常量則建議省略中括號,例如:
<user-detail detail="我是字符串常量" [user]="currentUser"></user-detail>
- 1
HTML標簽特性綁定:純粹的HTML標簽特性比如<table>
的colspan
采用和DOM
一樣的綁定方式會報錯,例如:
//以下模板會出現解析錯誤 <table> <tr> <td colspan="{{ 1 + 2 }}"></td> </tr> </table> //正確的HTML標簽特性綁定 <table> <tr> <td [attr.colspan]="{{ 1 + 2 }}"></td> </tr> </table>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
HTML標簽特性綁定類似於屬性綁定,但是中括號的部分不是一個元素的屬性名,而是由attr.
前綴和HTML元素特性名稱組成的形式。
CSS類綁定:CSS類既屬於DOM對象屬性,也屬於HTML標簽特性,所以可以使用以上兩種方式綁定:
<div class='red font14' [class]="changeGreen">14號 綠色字</div>
- 1
特有的綁定方式:[class.class-name]語法,被賦值為true時,將class-name這個類添加到該綁定的標簽上,否則移除這個類。
<div [class.class-blue]="isBlue()">若isBlue()返回true,這里的字體將變成藍色</div>
<div class="footer" [class.footer]="showFooter">若showFooter為false,則footer這個css被移除</div>
- 1
- 2
- 3
Style樣式綁定:HTML標簽內聯樣式可以通過Style
樣式綁定的方式設置。語法為[style.style-property],可以帶單位如px和%:
<button [style.background-color]="canClick ? 'blue' : 'red'">若canClick為true,則按鈕背景顏色為藍色</button>
<button [style.font-size.px]="isLarge ? 18 : 13">若isLarge為true,則按鈕字體變為18px</button>
- 1
- 2
- 3
2.4 事件綁定
單向,數據從模板到組件類流動。Angular監聽用戶操作時間,如鍵盤事件、鼠標事件、觸屏事件等方法。事件綁定的語法為:“=”左側小括號內的目標事件和“=”右側引號中的模板語句組成。
模板語句與模板表達式一樣,和JS表達式類似,有一些JS表達式在模板語句中不被支持:
- 賦值操作,如+=或-=
- 自增和自減操作符(++和–)
- new 操作符
- 位運算符 | 和 &
- 模板表達式運算符
模板語句和模板運算符一樣,只能訪問其上下文環境的成員,模板語句的上下文環境就是綁定事件對應組件的實例。也可以包含組件外的對象,如模板局部變量和事件綁定語句中的$event
目標事件:小括號中的事件名表示目標事件,還可以帶on-前綴的形式來標記目標事件,還可以是自定義指令的事件:
<a class="edit" (click)="editContact()"></a> <a class="edit" on-click="editContact()"></a> <a class="edit" (myClick)="editContact=$event"></a>
- 1
- 2
- 3
- 4
- 5
$event事件對象:$event
事件對象用來獲取事件的相關信息,如果目標事件是原生DOM元素事件(可以是自定義事件),則$event
將是一個包含了target
和target.value
屬性的DOM時間對象,例如:
<input [value]="currentUser.firstName" (input)="currentUser.firstName=$event.target.value"/>
- 1
自定義事件:借助EventEmitter
實現。它的實現步驟:一、在組件中創建EventEmitter
實例對象,並將其以輸出屬性形式暴露;二、父組件通過綁定一個屬性來自定義一個事件;三、在組件中調用EventEmitter.emit()
觸發自定義事件;四、父組件綁定的事件通過$event
對象訪問數據。
//父組件collection.component.ts import { Component } from '@angular/core'; @Component({ selector: 'collection', template: `<contact-collect [contact]="detail" (onCollect)="collectTheContact($event)"></contact-collect>` }) export class CollectionComponent implements OnInit{ detail: any = {}; collectTheContact(){ this.detail.collection == 0 ? this.detail.collection = 1 : this.detail.collection = 0; } } //子組件contactCollect.component.ts import { Component } from '@angular/core'; @Component({ selector: 'contact-collect', template: `<i [ngClass]="{collected: contact.collection}" (click)="collectTheContact()">收藏</i>` }) export class CollectionComponent implements OnInit{ @Input() contact: any = {}; @Output() onCollect = new EventEmitter<boolean>(); collectTheContact(){ this.onCollect.emit(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
子組件click
事件觸發collectTheContact
方法,該方法調用EventEmitter
實例化對象onCollect()
的emit
方法,向父組件發送數據;父組件綁定了子組件的onCollect
事件,該事件被觸發后將調用父元素的collectTheContact($event)
方法,並以$event
訪問數據。
2.5 雙向數據綁定
//最原始的實現方式 <input [value]="currentUser.firstName" (input)="currentUser.firstName=$event.target.value"/> //借助於NgModel,展開形式 <input [ngModel]="currentUser.phoneNumber" (ngModelChange)="currentUser.phoneNumver=$event"/> //最簡潔的方式 <input [(ngModel)]="currentUser.phoneNumber"/>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
[ ]實現了數據流從組件類到模板,( )實現了數據流從模板到組件類。
2.6 輸入輸出屬性
綁定聲明中,“=”左側的稱為綁定目標,“=”右側稱為綁定源。
//list.component.html
<list-item [contact]="contact" (routerNavigate)="routerNavigate($event)"></list-item>
- 1
- 2
list-item
中,數據通過模板表達式流向目標屬性contact
,因而contact
在ListComponent
中是一個輸入屬性。而事件綁定中,數據流向routerNavigate
綁定源,傳遞給接收者,routerNavigate
是一個輸出屬性。
綁定目標必須被明確地標記為輸入或輸出屬性,可以以修飾符(@Input
和@Output
)或組件元數據(inputs
和outputs
)兩種方式聲明。
//goto是別名
@Output('goto') clicks = new EventEmitter<number>();
//元數據方式
@Component({
outputs: ['clicks:goto']
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3 內置指令
NgClass:通過它,可以動態添加或移除多個類。NgClass
綁定一個由CSS
類名:value
的對象,value是一個布爾類型的數據值,當value
為true
時添加對應的類名到模板元素中,反之刪除。
setClasses(){ let classes={ red: this.red, font14: !this.font14, title: this.isTitle } return classes } <div [ngClass]="setClass()"></div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
NgStyle:設置多個內聯樣式。綁定刑如CSS
屬性名:value
的對象。
setStyles(){ let styles = { 'color': this.red ? 'red' : 'blue', 'font-size': !this.font14 ? '14px' : '16px', 'font-weight': this.isSpecial ? 'bold' : 'normal' }; return styles; } <div [ngStyle]="setStyles"></div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
NgIf:綁定一個布爾類型的表達式,當表達式真時候,DOM樹節點上添加一個元素及其子元素,否則移除(查看DOM樹不能看到該元素)。
<div *ngIf="collect.length === 0"></div>
- 1
NgStitch:根據NgSwitch
綁定的模板表達式返回值決定添加那個模板元素到DOM節點上。
<span [ngSwitch]="contactName"> <span *ngSwitchCase="'TimCook'">蒂姆·庫克</span> <span *ngSwitchCase="'BillGates'">比爾蓋茨</span> <span *ngSwitchDefault>無名氏</span> </span>
- 1
- 2
- 3
- 4
- 5
NgFor:重復執行某些步驟來展現數據,它支持一個可選的index索引,下標范圍為0<=index<數組的長度。
<div *ngFor="let contact of contacts;let i=index">{{i + 1}} - {{ contact.id }}</div>
- 1
NgForTrackBy:每次更改都會引發很多相關聯的DOM操作,使用NgFor
會讓性能變得很差,比如重新從服務器拉取列表數據,雖然大部分數據沒變化,但是因為不知道哪些數據變化了,需要清空並重新渲染。可以通過使用追蹤函數避免重復渲染的性能浪費。
trackByContacts(index: number, contact: Contact){ return contact.id; } <div *ngFor="let contact of contacts; trackBy: trackByContacts">{{ contact.id }}</div>
- 1
- 2
- 3
- 4
- 5
4 表單
HTML內置表單標簽一些特性存在瀏覽器兼容性問題,在自定義規則、表單數據獲取、處理、提交等流程都比較復雜。Angualr提供了雙向數據綁定、強大的檢驗規則以及自定義檢驗錯誤提示等功能。Angular提供了模板驅動(使用模板表單內置指令、內置檢驗方式)和模型驅動(自定義)兩種方式構建表單。
4.1 一個模板表單例子
@Component{ selector: 'add-content', template: ` <h3>添加聯系人</h3> <form> <ul> <li> <label for="name">姓名:</label> <input type='text' name='name'/> </li> <!--...--> <li> <button type='submit'>添加</button> <button type='button'>取消</button> </li> </ul> </form> ` } export class FormComponent {}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
4.2 表單指令
NgForm:表單控制中心,負責處理表單頁面邏輯,擴展了額外表單特性,表單指令在NgForm
指令內部才能正常運行。
NgForm
的使用步驟如下:
- 在根模塊導入
FormsModule
模塊和FormComponent
組件 - 在
FormComponent
組件中直接使用NgForm
import { NgModule } from '@angular/core'; import { BrowserModule} from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent} from './app.component'; import { FormComponent} from './form.component'; @NgModule({ imports:[ BrowserModule, FormsModule ], declarations:[ AppComponent, FormComponent ] })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
NgModel:NgModel
實現了表單控件的數據綁定,提供了控件狀態跟蹤和檢驗功能。
<input type='text' name='contactName' [(ngModel)]="curContact.name"/>
- 1
控件中使用NgModel
,必須添加name
屬性,否則報錯。原因是,NgForm
指令為表單建立一個控件對象FormControl的集合,以此來作為表單控件的容器。控件的NgModel
屬性綁定會以name
作為唯一標識來注冊並生成一個FormControl
,並將其加入到FormControl
的集合中。
單選框:NgModel
會綁定選中的單選框的值
<input type='radio' name="sex" [(ngModel)]="curContact.sex" value="female" />女
<input type='radio' name="sex" [(ngModel)]="curContact.sex" value="male" />男
- 1
- 2
復選框:NgModel
會綁定一個布爾值
<input type='checkbox' name="lock" [(ngModel)]="curContact.lock" />
- 1
單選下拉框:option
綁定目標有兩種,value
和ngValue
,value
返回值類型為基本數據類型,ngValue
返回值為對象數據類型。
//第一步:定義下拉框列表所需的數據 export class FormComponent { interests:any[] = [ {value: 'reading', display: '閱讀'}, {value: 'traveling', display: '旅游'}, {value: 'sport', display: '運動'} ] } //第二步:構建下拉框模板 <select name="interestValue" [(ngModel)]="curContact.interestValue"> <option *ngFor="let interst of intersts" [value]="interest.value"> {{interest.display}} </option> </select>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
多選下拉框: 與單選下拉框類似,不過返回值為選中數據的數組。
模板局部變量:模板中對DOM元素或指令(包括組件)的引用(作用類似於getElementById
),可以使用在當前元素、兄弟元素或任何子元素中。
DOM元素局部變量:局部變量名前加#符號或者加ref-前綴
<input type='text' #contactName name="contactName" id="contactName"/>
<input type='number' ref-telNum name="telNum" id="telNum"/>
- 1
- 2
表單指令局部變量:表單指令的局部變量在定義時需手動初始化為特定指令的代表值,最終解析后會被賦值為表單指令實例對象的引用。
- NgForm表單局部變量
<form #contactForm="ngForm">
//...
</form>
- 1
- 2
- 3
局部變量#contactForm
為NgForm
指令實例對象的引用,可以在模板中讀取NgForm
實例對象的屬性值,如追蹤表單的valid
屬性狀態。
- NgModel控件局部變量
<input type='text' name="contactName" [(ngModel)]="curContact.name" #contactName="ngModel"/> <p>{{ contactName.valid }}</p>
- 1
- 2
局部變量contactName
是NgModel
指令實例對象的引用,可以通過它讀取NgModel
的屬性值。
表單狀態:NgForm
和NgModel
指令都可以用於追蹤表單狀態來實現數據檢驗,他們都有五個表示狀態的屬性,屬性值為布爾類型,可通過對應的局部變量來獲取。NgForm
追蹤的是整個表單控件的狀態,NgModel
追蹤單個控件。
valid
:表單值是否改變pristine
:表單值是否未改變dirty
:表單值是否已改變touched
:表單是否已被訪問過untouched
:表單時是否未被訪問過
表單狀態檢驗有三個時段,初始狀態、輸入后狀態(valid
、pristine
、dirty
狀態改變)、失去焦點后狀態(touched
和untouched
狀態改變)。
NgModelGroup指令:對表單輸入內容進行分組,方便在語義上區分不同類型的輸入。
<fieldset ngModelGroup="nameGroup" #nameGroup="ngModelGroup"> <label>姓:</label> <input type='text' name="firstName" [(ngModel)]="curContact.firstName" required/> <label>名:</label> <input type='text' name="lastName" [(ngModel)]="curContact.lastName" required/> </fieldset> 1 2 3 4 5 6 //這是form中的數據格式 { nameGroup: { firstName: '', lastName: '' } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
ngSubmit事件:
<form #contactForm="ngForm" (ngSubmit)="doSubmit(contactForm.value)"> <li> <button type='submit' [disabled]="!contactForm.value"> 添加 </button> <button type='reset'>重置</button> </li> </form> export class FormComponent{ doSubmit(formValue: any){ } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
4.3 自定義表單樣式
.ng-valid[required] { border-left: 5px solid #0f0; } .ng-invalid { border-left: 5px solid #f00; } <p [hidden]="contactName.valid || contactName.pristine">用戶名長度為3-10個字符</p>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
4.4 表單檢驗
表單內置檢驗:required
、minlength
、maxlength
、pattern
表單自定義檢驗
- 創建自定義檢驗
//validate-username.ts import { FormControl } from '@angular/forms'; const EMAIL_REGEXP = new RegExp("[a-z0-9]+@[a-z0-9]+.com"); const TEL_REGEXP = new RegExp("1[0-9]{10}"); export function validateUserName(c: FormControl) { return (EMAIL_REGEXP.test(c.value) || TEL_REGEXP.test(c.value)) ? null : { userName: { valid: false, errorMsg: '用戶名必須是手機號或者郵箱賬號' } }; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 使用自定義檢驗
//... import { ReactiveFormsModule } from '@angular/forms'; import { FormComponent } from './form.component'; import { AppComponent} from './app.component'; @NgModule({ imports: [BrowserModule, ReactiveFormsModule], declarations: [AppComponent, FormComponent], bootstrap: [AppComponent] }) export class AppModule {}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
首先要導入ReactiveFormsModule
import { Component } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; import { validateUserName } from './validate-username'; @Component({ selector: 'add-contact', template: ` <form [formGroup]="customForm"> <label>姓名:</label> <input type='text' formControlName='customName'/> </form> ` }) export class FormComponent{ customForm = new FormGroup({ customName: new FormControl('', validateUserName) }); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
分別定義了FormGroup
和FormControl
的實例化對象
5 管道
Angular中,管道可以按照開發者指定的規則將模板內的數據進行轉換。
5.1 什么是管道
模板中,通過管道操作符 | 使用管道,| 左邊的為輸入數 據,右邊為管道。管道可以帶有參數,通過傳入參數輸出不同格式數據。同時,模板表達式中可以同時使用多個管道進行不同的處理。
<p>{{ birthday | date }}</p> <P>{{ birthday | data:"MM/dd/y" }}</p> <p>{{ expression | pipeName1 | pipeName2 }}</p>
- 1
- 2
- 3
- 4
- 5
5.2 幾種管道
內置管道:Angular提供的,不需導入可以直接使用。
- DatePipe:日期管道,格式化日期,純管道
- JsonPipe:將輸入數據對象經過JSON.stringify()方法轉換后輸出對象字符串,非純管道
- UpperCasePipe:文本中所有小寫字母全轉換為字母,純
- LowerCasePipe:變成小寫,純
- DecimalPipe:將數值按特定格式顯示文本,純
- CurrencyPipe:數值轉化為本地貨幣格式,純
- PercentPipe:數值轉百分比,純
- SlicePipe:將數值或者字符串裁剪成新的子集,非純管道
expression | date: format expression | json expression | uppercase expression | lowercase expression | number[: digitInfo] expression | currency[: currencyCode[: symbolDisplay[: digitInfo]]] expression | percent expression | slice: start[: end]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
自定義管道:通過以下幾個步驟實現
- 定義元數據:引入Pipe和PipeTransform,同時為管道命名
//sexreform.pipe.ts import { Pipe, PipeTransform } from "@angular/core"; @Pipe { name: 'sexReform' } export class SexReform implements PipeTransform { //... }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 實現transform方法
export class SexReform implements PipeTransform { transform(val: string): string { switch(val) { case 'male': return '男'; case 'female' return '女'; default: return '未知性別'; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 使用自定義管道
//使用管道前,需要在@NgModule的元數據declarations數組中添加自定義管道 import { SexReform } from 'pipes/sexreform.pipe'; @NgModule ({ //... declarations: [SexReform] }) //可以像內置管道一般使用自定義管道咯 @Component ({ selector: 'pipe-demo-custom', template: ` <p>{{ sexValue | sexReform }}</p> ` })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
純管道與非純管道的區別:只有發生純變才會調用該管道,這類管道稱為純管道,其余的管道成為非純管道。純變指的是對基本數據類型(String、Number、Boolean)輸入值的變更或者對對象引用(Array、Function、Object)的更改。
只要數據發生改變,均會觸發非純管道,但不一定會觸發純管道,需要考察數據變化的情形是否為純變化。看下面這個例子:
//... @Component ({ selector: 'pure-pipe-demo', template: ` <div> <p>{{ dateObj | date: "y-MM-dd HH:mm:ss EEEE" }}</p> <p>{{ dateStr | date: "y-MM-dd HH:mm:ss EEEE" }}</p> </div> ` }) export class PurePipeDemoComponent { dateObj: date = new Date('2016-06-08 20:05:08'); dateStr: string = '2016-06-08 20:05:08'; constructor(){ setTimeout(() => { this.dateObj.setMonth(11), this.dateStr = '2016-12-08 20:05:08' },2000); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
初始日期分別為:
'2016-06-08 20:05:08 Wednesday'
'2016-06-08 20:05:08 Wednesday'
- 1
- 2
2s之后變成了
'2016-06-08 20:05:08 Wednesday'
'2016-12-08 20:05:08 Thursday'
- 1
- 2
1 什么是模板
它是頁面呈現的骨架,是盛裝組件數據的容器。與之相關的內容包括了模板與組件件數據交互、內置指令、表單、管道等。
1.1 模板語法概覽
//插值:綁定屬性變量的值到模板中 <p>{{ detail.telNum }}</p> //DOM元素屬性綁定:將模板表達式name的值綁定到元素<div>的屬性title上 <div [title]="name"></div> //HTML標簽特性綁定:將模板表達式的返回值綁定到元素<td>標簽特性colspan上 <td [attr.colspan]="{{ 1+2 }}">合並單元格</td> //Class類綁定:當isBlue()函數值為true時為div添加類名為isBlue的樣式 <div [class.isblue]="isBlue()"></div> //Style樣式綁定:當表達式isRed的值為為true時設置button的文字顏色為紅色,否則為綠色 <button [style.color]="isRed ? 'red':'green'">紅色</button> //事件綁定:單擊元素時會觸發click事件,需要時也可以傳遞$event對象,如(click)="editContact($event)" <a class='edit' (click)="editContact()"></a> //雙向綁定:組件和模板間雙向數據綁定,等價於<div [title]="name" (titleChange)="name=$event"></div> <div [(title)]="name"></div> //模板局部變量:在當前模板中創建一個對id值為name的input元素的引用變量name,相當於document.getElementById("name") <input type='text' ##name name="name" id="name"/> //管道操作符:原始數據birthday經管道轉換后輸出期望數據並顯示在模板中 <p>張三的生日是{{ birthday | date }}</p> //模板表達式操作符:模板表達式操作符表明detail.telNum屬性不是必須存在的,如果它的值是undefined,那么后面的表達式將會被忽略,不會引發異常 <p>{{ detail?.telNum }}</p> //星號前綴:使用星號前綴可以簡化對結構指令的使用,Angular會將帶有星號的指令引用替換成帶有<template>標簽的代碼,等價於<template [myUnless]="boolValue"><p>myUnless is false now.</p></template> <p *myUnless="boolValue">myUnless is false now.</p>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
2 數據綁定
根據數據流向可以分為三種:
- 單向:數據源到視圖
//插值DOM元素屬性 <p>{{ detail.telNum }}</P> //綁定HTML標簽特性 <div [title]="name"></div> //綁定 <div [style.color]="color">hello world</div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 單向:從視圖目標到數據源
//事件綁定
(click)="editContact()"
on-click="editContact()"
- 1
- 2
- 3
- 雙向
//雙向綁定
<div [(title)]="name"></div>
<div bindon-title="name"></div>
- 1
- 2
- 3
NOTE
Property為DOM對象屬性,以DOM元素作為多想,其附加內容,是在文檔對象模型里定義的,如childNodes、firstChild。 而Attribute為HTML標簽特性,是DOM節點自帶的屬性,在HTML中定義的,即只要是在HTML標簽中出現的屬性(HTML代碼)都是Attribute。
數據綁定是借助於DOM對象屬性和事件來運作的。
2.1 插值
雙大括號{{ }}語法來實現。
2.2 模板表達式
類似於JS的表達式,絕大多數JS表達式均為合法模板表達式。它應用於插值語法雙大括號中和屬性綁定“=”右側的括號中。但以下JS表達式不是合法模板表達式:
- 帶有new運算符的表達式
- 賦值表達式
- 帶有 ; 或者 , 的鏈式表達式
- 帶有自增自減
模板表達式不支持位運算。
2.3 屬性綁定
DOM元素屬性綁定:把DOM對象屬性綁定到組件的屬性上,而綁定目標可以是中括號,也可以加前綴,還可以使用屬性綁定設置自定義組件的輸入屬性。
//中括號 <div [title]="titleText"></div> //加前綴 <div bind-title="titleText"></div> //自定義組件的輸入屬性 <user-detail [user]="currentUser"></user-detail>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
NOTE:
中括號的作用是計算右側模板表達式,如果沒有中括號,右側表達式會被當成字符串常量,如果是字符串常量則建議省略中括號,例如:
<user-detail detail="我是字符串常量" [user]="currentUser"></user-detail>
- 1
HTML標簽特性綁定:純粹的HTML標簽特性比如<table>
的colspan
采用和DOM
一樣的綁定方式會報錯,例如:
//以下模板會出現解析錯誤 <table> <tr> <td colspan="{{ 1 + 2 }}"></td> </tr> </table> //正確的HTML標簽特性綁定 <table> <tr> <td [attr.colspan]="{{ 1 + 2 }}"></td> </tr> </table>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
HTML標簽特性綁定類似於屬性綁定,但是中括號的部分不是一個元素的屬性名,而是由attr.
前綴和HTML元素特性名稱組成的形式。
CSS類綁定:CSS類既屬於DOM對象屬性,也屬於HTML標簽特性,所以可以使用以上兩種方式綁定:
<div class='red font14' [class]="changeGreen">14號 綠色字</div>
- 1
特有的綁定方式:[class.class-name]語法,被賦值為true時,將class-name這個類添加到該綁定的標簽上,否則移除這個類。
<div [class.class-blue]="isBlue()">若isBlue()返回true,這里的字體將變成藍色</div>
<div class="footer" [class.footer]="showFooter">若showFooter為false,則footer這個css被移除</div>
- 1
- 2
- 3
Style樣式綁定:HTML標簽內聯樣式可以通過Style
樣式綁定的方式設置。語法為[style.style-property],可以帶單位如px和%:
<button [style.background-color]="canClick ? 'blue' : 'red'">若canClick為true,則按鈕背景顏色為藍色</button>
<button [style.font-size.px]="isLarge ? 18 : 13">若isLarge為true,則按鈕字體變為18px</button>
- 1
- 2
- 3
2.4 事件綁定
單向,數據從模板到組件類流動。Angular監聽用戶操作時間,如鍵盤事件、鼠標事件、觸屏事件等方法。事件綁定的語法為:“=”左側小括號內的目標事件和“=”右側引號中的模板語句組成。
模板語句與模板表達式一樣,和JS表達式類似,有一些JS表達式在模板語句中不被支持:
- 賦值操作,如+=或-=
- 自增和自減操作符(++和–)
- new 操作符
- 位運算符 | 和 &
- 模板表達式運算符
模板語句和模板運算符一樣,只能訪問其上下文環境的成員,模板語句的上下文環境就是綁定事件對應組件的實例。也可以包含組件外的對象,如模板局部變量和事件綁定語句中的$event
目標事件:小括號中的事件名表示目標事件,還可以帶on-前綴的形式來標記目標事件,還可以是自定義指令的事件:
<a class="edit" (click)="editContact()"></a>
<a class="edit" on-click="editContact()"></a>
<a class="edit" (myClick)="editContact=$event"></a>
- 1
- 2
- 3
- 4
- 5
$event事件對象:$event
事件對象用來獲取事件的相關信息,如果目標事件是原生DOM元素事件(可以是自定義事件),則$event
將是一個包含了target
和target.value
屬性的DOM時間對象,例如:
<input [value]="currentUser.firstName" (input)="currentUser.firstName=$event.target.value"/>
- 1
自定義事件:借助EventEmitter
實現。它的實現步驟:一、在組件中創建EventEmitter
實例對象,並將其以輸出屬性形式暴露;二、父組件通過綁定一個屬性來自定義一個事件;三、在組件中調用EventEmitter.emit()
觸發自定義事件;四、父組件綁定的事件通過$event
對象訪問數據。
//父組件collection.component.ts import { Component } from '@angular/core'; @Component({ selector: 'collection', template: ` <contact-collect [contact]="detail" (onCollect)="collectTheContact($event)"></contact-collect> ` }) export class CollectionComponent implements OnInit{ detail: any = {}; collectTheContact(){ this.detail.collection == 0 ? this.detail.collection = 1 : this.detail.collection = 0; } } //子組件contactCollect.component.ts import { Component } from '@angular/core'; @Component({ selector: 'contact-collect', template: ` <i [ngClass]="{collected: contact.collection}" (click)="collectTheContact()">收藏</i> ` }) export class CollectionComponent implements OnInit{ @Input() contact: any = {}; @Output() onCollect = new EventEmitter<boolean>(); collectTheContact(){ this.onCollect.emit(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
子組件click
事件觸發collectTheContact
方法,該方法調用EventEmitter
實例化對象onCollect()
的emit
方法,向父組件發送數據;父組件綁定了子組件的onCollect
事件,該事件被觸發后將調用父元素的collectTheContact($event)
方法,並以$event
訪問數據。
2.5 雙向數據綁定
//最原始的實現方式 <input [value]="currentUser.firstName" (input)="currentUser.firstName=$event.target.value"/> //借助於NgModel,展開形式 <input [ngModel]="currentUser.phoneNumber" (ngModelChange)="currentUser.phoneNumver=$event"/> //最簡潔的方式 <input [(ngModel)]="currentUser.phoneNumber"/>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
[ ]實現了數據流從組件類到模板,( )實現了數據流從模板到組件類。
2.6 輸入輸出屬性
綁定聲明中,“=”左側的稱為綁定目標,“=”右側稱為綁定源。
//list.component.html
<list-item [contact]="contact" (routerNavigate)="routerNavigate($event)"></list-item>
- 1
- 2
list-item
中,數據通過模板表達式流向目標屬性contact
,因而contact
在ListComponent
中是一個輸入屬性。而事件綁定中,數據流向routerNavigate
綁定源,傳遞給接收者,routerNavigate
是一個輸出屬性。
綁定目標必須被明確地標記為輸入或輸出屬性,可以以修飾符(@Input
和@Output
)或組件元數據(inputs
和outputs
)兩種方式聲明。
//goto是別名 @Output('goto') clicks = new EventEmitter<number>(); //元數據方式 @Component({ outputs: ['clicks:goto'] })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3 內置指令
NgClass:通過它,可以動態添加或移除多個類。NgClass
綁定一個由CSS
類名:value
的對象,value是一個布爾類型的數據值,當value
為true
時添加對應的類名到模板元素中,反之刪除。
setClasses(){ let classes={ red: this.red, font14: !this.font14, title: this.isTitle } return classes } <div [ngClass]="setClass()"></div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
NgStyle:設置多個內聯樣式。綁定刑如CSS
屬性名:value
的對象。
setStyles(){ let styles = { 'color': this.red ? 'red' : 'blue', 'font-size': !this.font14 ? '14px' : '16px', 'font-weight': this.isSpecial ? 'bold' : 'normal' }; return styles; } <div [ngStyle]="setStyles"></div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
NgIf:綁定一個布爾類型的表達式,當表達式真時候,DOM樹節點上添加一個元素及其子元素,否則移除(查看DOM樹不能看到該元素)。
<div *ngIf="collect.length === 0"></div>
- 1
NgStitch:根據NgSwitch
綁定的模板表達式返回值決定添加那個模板元素到DOM節點上。
<span [ngSwitch]="contactName">
<span *ngSwitchCase="'TimCook'">蒂姆·庫克</span>
<span *ngSwitchCase="'BillGates'">比爾蓋茨</span>
<span *ngSwitchDefault>無名氏</span>
</span>
- 1
- 2
- 3
- 4
- 5
NgFor:重復執行某些步驟來展現數據,它支持一個可選的index索引,下標范圍為0<=index<數組的長度。
<div *ngFor="let contact of contacts;let i=index">{{i + 1}} - {{ contact.id }}</div>
- 1
NgForTrackBy:每次更改都會引發很多相關聯的DOM操作,使用NgFor
會讓性能變得很差,比如重新從服務器拉取列表數據,雖然大部分數據沒變化,但是因為不知道哪些數據變化了,需要清空並重新渲染。可以通過使用追蹤函數避免重復渲染的性能浪費。
trackByContacts(index: number, contact: Contact){
return contact.id;
}
<div *ngFor="let contact of contacts; trackBy: trackByContacts">{{ contact.id }}</div>
- 1
- 2
- 3
- 4
- 5
4 表單
HTML內置表單標簽一些特性存在瀏覽器兼容性問題,在自定義規則、表單數據獲取、處理、提交等流程都比較復雜。Angualr提供了雙向數據綁定、強大的檢驗規則以及自定義檢驗錯誤提示等功能。Angular提供了模板驅動(使用模板表單內置指令、內置檢驗方式)和模型驅動(自定義)兩種方式構建表單。
4.1 一個模板表單例子
@Component{ selector: 'add-content', template: ` <h3>添加聯系人</h3> <form> <ul> <li> <label for="name">姓名:</label> <input type='text' name='name'/> </li> <!--...--> <li> <button type='submit'>添加</button> <button type='button'>取消</button> </li> </ul> </form> ` } export class FormComponent {}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
4.2 表單指令
NgForm:表單控制中心,負責處理表單頁面邏輯,擴展了額外表單特性,表單指令在NgForm
指令內部才能正常運行。
NgForm
的使用步驟如下:
- 在根模塊導入
FormsModule
模塊和FormComponent
組件 - 在
FormComponent
組件中直接使用NgForm
import { NgModule } from '@angular/core'; import { BrowserModule} from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent} from './app.component'; import { FormComponent} from './form.component'; @NgModule({ imports:[ BrowserModule, FormsModule ], declarations:[ AppComponent, FormComponent ] })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
NgModel:NgModel
實現了表單控件的數據綁定,提供了控件狀態跟蹤和檢驗功能。
<input type='text' name='contactName' [(ngModel)]="curContact.name"/>
- 1
控件中使用NgModel
,必須添加name
屬性,否則報錯。原因是,NgForm
指令為表單建立一個控件對象FormControl的集合,以此來作為表單控件的容器。控件的NgModel
屬性綁定會以name
作為唯一標識來注冊並生成一個FormControl
,並將其加入到FormControl
的集合中。
單選框:NgModel
會綁定選中的單選框的值
<input type='radio' name="sex" [(ngModel)]="curContact.sex" value="female" />女
<input type='radio' name="sex" [(ngModel)]="curContact.sex" value="male" />男
- 1
- 2
復選框:NgModel
會綁定一個布爾值
<input type='checkbox' name="lock" [(ngModel)]="curContact.lock" />
- 1
單選下拉框:option
綁定目標有兩種,value
和ngValue
,value
返回值類型為基本數據類型,ngValue
返回值為對象數據類型。
//第一步:定義下拉框列表所需的數據 export class FormComponent { interests:any[] = [ {value: 'reading', display: '閱讀'}, {value: 'traveling', display: '旅游'}, {value: 'sport', display: '運動'} ] } //第二步:構建下拉框模板 <select name="interestValue" [(ngModel)]="curContact.interestValue"> <option *ngFor="let interst of intersts" [value]="interest.value"> {{interest.display}} </option> </select>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
多選下拉框: 與單選下拉框類似,不過返回值為選中數據的數組。
模板局部變量:模板中對DOM元素或指令(包括組件)的引用(作用類似於getElementById
),可以使用在當前元素、兄弟元素或任何子元素中。
DOM元素局部變量:局部變量名前加#符號或者加ref-前綴
<input type='text' #contactName name="contactName" id="contactName"/>
<input type='number' ref-telNum name="telNum" id="telNum"/>
- 1
- 2
表單指令局部變量:表單指令的局部變量在定義時需手動初始化為特定指令的代表值,最終解析后會被賦值為表單指令實例對象的引用。
- NgForm表單局部變量
<form #contactForm="ngForm">
//...
</form>
- 1
- 2
- 3
局部變量#contactForm
為NgForm
指令實例對象的引用,可以在模板中讀取NgForm
實例對象的屬性值,如追蹤表單的valid
屬性狀態。
- NgModel控件局部變量
<input type='text' name="contactName" [(ngModel)]="curContact.name" #contactName="ngModel"/> <p>{{ contactName.valid }}</p>
- 1
- 2
局部變量contactName
是NgModel
指令實例對象的引用,可以通過它讀取NgModel
的屬性值。
表單狀態:NgForm
和NgModel
指令都可以用於追蹤表單狀態來實現數據檢驗,他們都有五個表示狀態的屬性,屬性值為布爾類型,可通過對應的局部變量來獲取。NgForm
追蹤的是整個表單控件的狀態,NgModel
追蹤單個控件。
valid
:表單值是否改變pristine
:表單值是否未改變dirty
:表單值是否已改變touched
:表單是否已被訪問過untouched
:表單時是否未被訪問過
表單狀態檢驗有三個時段,初始狀態、輸入后狀態(valid
、pristine
、dirty
狀態改變)、失去焦點后狀態(touched
和untouched
狀態改變)。
NgModelGroup指令:對表單輸入內容進行分組,方便在語義上區分不同類型的輸入。
<fieldset ngModelGroup="nameGroup" #nameGroup="ngModelGroup"> <label>姓:</label> <input type='text' name="firstName" [(ngModel)]="curContact.firstName" required/> <label>名:</label> <input type='text' name="lastName" [(ngModel)]="curContact.lastName" required/> </fieldset> 1 2 3 4 5 6 //這是form中的數據格式 { nameGroup: { firstName: '', lastName: '' } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
ngSubmit事件:
<form #contactForm="ngForm" (ngSubmit)="doSubmit(contactForm.value)"> <li> <button type='submit' [disabled]="!contactForm.value"> 添加 </button> <button type='reset'>重置</button> </li> </form> export class FormComponent{ doSubmit(formValue: any){ } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
4.3 自定義表單樣式
.ng-valid[required] { border-left: 5px solid #0f0; } .ng-invalid { border-left: 5px solid #f00; } <p [hidden]="contactName.valid || contactName.pristine">用戶名長度為3-10個字符</p>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
4.4 表單檢驗
表單內置檢驗:required
、minlength
、maxlength
、pattern
表單自定義檢驗
- 創建自定義檢驗
//validate-username.ts import { FormControl } from '@angular/forms'; const EMAIL_REGEXP = new RegExp("[a-z0-9]+@[a-z0-9]+.com"); const TEL_REGEXP = new RegExp("1[0-9]{10}"); export function validateUserName(c: FormControl) { return (EMAIL_REGEXP.test(c.value) || TEL_REGEXP.test(c.value)) ? null : { userName: { valid: false, errorMsg: '用戶名必須是手機號或者郵箱賬號' } }; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 使用自定義檢驗
//... import { ReactiveFormsModule } from '@angular/forms'; import { FormComponent } from './form.component'; import { AppComponent} from './app.component'; @NgModule({ imports: [BrowserModule, ReactiveFormsModule], declarations: [AppComponent, FormComponent], bootstrap: [AppComponent] }) export class AppModule {}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
首先要導入ReactiveFormsModule
import { Component } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; import { validateUserName } from './validate-username'; @Component({ selector: 'add-contact', template: ` <form [formGroup]="customForm"> <label>姓名:</label> <input type='text' formControlName='customName'/> </form> ` }) export class FormComponent{ customForm = new FormGroup({ customName: new FormControl('', validateUserName) }); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
分別定義了FormGroup
和FormControl
的實例化對象
5 管道
Angular中,管道可以按照開發者指定的規則將模板內的數據進行轉換。
5.1 什么是管道
模板中,通過管道操作符 | 使用管道,| 左邊的為輸入數 據,右邊為管道。管道可以帶有參數,通過傳入參數輸出不同格式數據。同時,模板表達式中可以同時使用多個管道進行不同的處理。
<p>{{ birthday | date }}</p> <P>{{ birthday | data:"MM/dd/y" }}</p> <p>{{ expression | pipeName1 | pipeName2 }}</p>
- 1
- 2
- 3
- 4
- 5
5.2 幾種管道
內置管道:Angular提供的,不需導入可以直接使用。
- DatePipe:日期管道,格式化日期,純管道
- JsonPipe:將輸入數據對象經過JSON.stringify()方法轉換后輸出對象字符串,非純管道
- UpperCasePipe:文本中所有小寫字母全轉換為字母,純
- LowerCasePipe:變成小寫,純
- DecimalPipe:將數值按特定格式顯示文本,純
- CurrencyPipe:數值轉化為本地貨幣格式,純
- PercentPipe:數值轉百分比,純
- SlicePipe:將數值或者字符串裁剪成新的子集,非純管道
expression | date: format expression | json expression | uppercase expression | lowercase expression | number[: digitInfo] expression | currency[: currencyCode[: symbolDisplay[: digitInfo]]] expression | percent expression | slice: start[: end]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
自定義管道:通過以下幾個步驟實現
- 定義元數據:引入Pipe和PipeTransform,同時為管道命名
//sexreform.pipe.ts import { Pipe, PipeTransform } from "@angular/core"; @Pipe { name: 'sexReform' } export class SexReform implements PipeTransform { //... }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 實現transform方法
export class SexReform implements PipeTransform { transform(val: string): string { switch(val) { case 'male': return '男'; case 'female' return '女'; default: return '未知性別'; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 使用自定義管道
//使用管道前,需要在@NgModule的元數據declarations數組中添加自定義管道 import { SexReform } from 'pipes/sexreform.pipe'; @NgModule ({ //... declarations: [SexReform] }) //可以像內置管道一般使用自定義管道咯 @Component ({ selector: 'pipe-demo-custom', template: ` <p>{{ sexValue | sexReform }}</p> ` })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
純管道與非純管道的區別:只有發生純變才會調用該管道,這類管道稱為純管道,其余的管道成為非純管道。純變指的是對基本數據類型(String、Number、Boolean)輸入值的變更或者對對象引用(Array、Function、Object)的更改。
只要數據發生改變,均會觸發非純管道,但不一定會觸發純管道,需要考察數據變化的情形是否為純變化。看下面這個例子:
//... @Component ({ selector: 'pure-pipe-demo', template: ` <div> <p>{{ dateObj | date: "y-MM-dd HH:mm:ss EEEE" }}</p> <p>{{ dateStr | date: "y-MM-dd HH:mm:ss EEEE" }}</p> </div> ` }) export class PurePipeDemoComponent { dateObj: date = new Date('2016-06-08 20:05:08'); dateStr: string = '2016-06-08 20:05:08'; constructor(){ setTimeout(() => { this.dateObj.setMonth(11), this.dateStr = '2016-12-08 20:05:08' },2000); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
初始日期分別為:
'2016-06-08 20:05:08 Wednesday'
'2016-06-08 20:05:08 Wednesday'
- 1
- 2
2s之后變成了
'2016-06-08 20:05:08 Wednesday'
'2016-12-08 20:05:08 Thursday'
- 1
- 2
你猜這是為什么呢??????