它是頁面呈現的骨架,是盛裝組件數據的容器。與之相關的內容包括了模板與組件件數據交互、內置指令、表單、管道等。css
//插值:綁定屬性變量的值到模板中 <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>
根據數據流向能夠分爲三種:html
//插值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>
NOTE git
Property
爲DOM
對象屬性,以DOM
元素做爲多想,其附加內容,是在文檔對象模型裏定義的,如childNodes、firstChild
。 而Attribute
爲HTML標籤特性,是DOM
節點自帶的屬性,在HTML中定義的,即只要是在HTML標籤中出現的屬性(HTML代碼)都是Attribute。express
數據綁定是藉助於DOM對象屬性和事件來運做的。json
雙大括號{{ }}語法來實現。bootstrap
相似於JS的表達式,絕大多數JS表達式均爲合法模板表達式。它應用於插值語法雙大括號中和屬性綁定「=」右側的括號中。但如下JS表達式不是合法模板表達式:數組
模板表達式不支持位運算。瀏覽器
DOM元素屬性綁定:把DOM對象屬性綁定到組件的屬性上,而綁定目標能夠是中括號,也能夠加前綴,還可使用屬性綁定設置自定義組件的輸入屬性。服務器
//中括號 <div [title]="titleText"></div> //加前綴 <div bind-title="titleText"></div> //自定義組件的輸入屬性 <user-detail [user]="currentUser"></user-detail>
NOTE:
中括號的做用是計算右側模板表達式,若是沒有中括號,右側表達式會被當成字符串常量,若是是字符串常量則建議省略中括號,例如:app
<user-detail detail="我是字符串常量" [user]="currentUser"></user-detail> 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>
HTML標籤特性綁定相似於屬性綁定,可是中括號的部分不是一個元素的屬性名,而是由attr.前綴和HTML元素特性名稱組成的形式。
CSS類綁定:CSS類既屬於DOM對象屬性,也屬於HTML標籤特性,因此可使用以上兩種方式綁定:
<div class='red font14' [class]="changeGreen">14號 綠色字</div>
特有的綁定方式:[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>
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>
單向,數據從模板到組件類流動。Angular監聽用戶操做時間,如鍵盤事件、鼠標事件、觸屏事件等方法。事件綁定的語法爲:「=」左側小括號內的目標事件和「=」右側引號中的模板語句組成。
模板語句與模板表達式同樣,和JS表達式相似,有一些JS表達式在模板語句中不被支持:
模板語句和模板運算符同樣,只能訪問其上下文環境的成員,模板語句的上下文環境就是綁定事件對應組件的實例。也能夠包含組件外的對象,如模板局部變量和事件綁定語句中的$event
目標事件:小括號中的事件名錶示目標事件,還能夠帶on-前綴的形式來標記目標事件,還能夠是自定義指令的事件:
<a class="edit" (click)="editContact()"></a> <a class="edit" on-click="editContact()"></a> <a class="edit" (myClick)="editContact=$event"></a> **$event事件對象**:$event事件對象用來獲取事件的相關信息,若是目標事件是原生DOM元素事件(能夠是自定義事件),則$event將是一個包含了target和target.value屬性的DOM時間對象,例如: <input [value]="currentUser.firstName" (input)="currentUser.firstName=$event.target.value"/>
自定義事件:藉助EventEmitter實現。它的實現步驟:1、在組件中建立EventEmitter實例對象,並將其以輸出屬性形式暴露;2、父組件經過綁定一個屬性來自定義一個事件;3、在組件中調用EventEmitter.emit()觸發自定義事件;4、父組件綁定的事件經過$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(); } } 子組件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"/> `[ ]`實現了數據流從組件類到模板,`( )`實現了數據流從模板到組件類。 ###2.6 輸入輸出屬性### 綁定聲明中,「=」左側的稱爲綁定目標,「=」右側稱爲綁定源。 //list.component.html <list-item [contact]="contact" (routerNavigate)="routerNavigate($event)"></list-item> list-item中,數據經過模板表達式流向目標屬性contact,於是contact在ListComponent中是一個輸入屬性。而事件綁定中,數據流向routerNavigate綁定源,傳遞給接收者,routerNavigate是一個輸出屬性。
綁定目標必須被明確地標記爲輸入或輸出屬性,能夠以修飾符(@Input和@Output)或組件元數據(inputs和outputs)兩種方式聲明。
//goto是別名 @Output('goto') clicks = new EventEmitter<number>(); //元數據方式 @Component({ outputs: ['clicks:goto'] })
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>
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>
NgIf
:綁定一個布爾類型的表達式,當表達式真時候,DOM樹節點上添加一個元素及其子元素,不然移除(查看DOM樹不能看到該元素)。
<div *ngIf="collect.length === 0"></div>
ngSwitch
:根據NgSwitch
綁定的模板表達式返回值決定添加那個模板元素到DOM
節點上。
<span [ngSwitch]="contactName"> <span *ngSwitchCase="'TimCook'">蒂姆·庫克</span> <span *ngSwitchCase="'BillGates'">比爾蓋茨</span> <span *ngSwitchDefault>無名氏</span> </span>
NgFor
:重複執行某些步驟來展示數據,它支持一個可選的index索引,下標範圍爲0<=index<數組的長度。
<div *ngFor="let contact of contacts;let i=index">{{i + 1}} - {{ contact.id }}</div>
NgForTrackBy
:每次更改都會引起不少相關聯的DOM操做,使用NgFor會讓性能變得不好,好比從新從服務器拉取列表數據,雖然大部分數據沒變化,可是由於不知道哪些數據變化了,須要清空並從新渲染。能夠經過使用追蹤函數避免重複渲染的性能浪費。
trackByContacts(index: number, contact: Contact){ return contact.id; } <div *ngFor="let contact of contacts; trackBy: trackByContacts">{{ contact.id }}</div>
HTML內置表單標籤一些特性存在瀏覽器兼容性問題,在自定義規則、表單數據獲取、處理、提交等流程都比較複雜。Angualr提供了雙向數據綁定、強大的檢驗規則以及自定義檢驗錯誤提示等功能。Angular提供了模板驅動(使用模板表單內置指令、內置檢驗方式)和模型驅動(自定義)兩種方式構建表單。
@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 {} ###4.2 表單指令###
NgForm:表單控制中心,負責處理表單頁面邏輯,擴展了額外表單特性,表單指令在NgForm指令內部才能正常運行。
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 ] }) NgModel:NgModel實現了表單控件的數據綁定,提供了控件狀態跟蹤和檢驗功能。 <input type='text' name='contactName' [(ngModel)]="curContact.name"/>
控件中使用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" />男
複選框:NgModel會綁定一個布爾值
<input type='checkbox' name="lock" [(ngModel)]="curContact.lock" />
單選下拉框: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>
多選下拉框: 與單選下拉框相似,不過返回值爲選中數據的數組。
模板局部變量:模板中對DOM元素或指令(包括組件)的引用(做用相似於getElementById),可使用在當前元素、兄弟元素或任何子元素中。
DOM元素局部變量:局部變量名前加#符號或者加ref-前綴
<input type='text' #contactName name="contactName" id="contactName"/> <input type='number' ref-telNum name="telNum" id="telNum"/>
表單指令局部變量:表單指令的局部變量在定義時需手動初始化爲特定指令的表明值,最終解析後會被賦值爲表單指令實例對象的引用。
<form #contactForm="ngForm"> //... </form>
局部變量#contactForm爲NgForm指令實例對象的引用,能夠在模板中讀取NgForm實例對象的屬性值,如追蹤表單的valid屬性狀態。
<input type='text' name="contactName" [(ngModel)]="curContact.name" #contactName="ngModel"/> <p>{{ contactName.valid }}</p>
局部變量contactName是NgModel指令實例對象的引用,能夠經過它讀取NgModel的屬性值。
表單狀態:NgForm和NgModel指令均可以用於追蹤表單狀態來實現數據檢驗,他們都有五個表示狀態的屬性,屬性值爲布爾類型,可經過對應的局部變量來獲取。NgForm追蹤的是整個表單控件的狀態,NgModel追蹤單個控件。
表單狀態檢驗有三個時段,初始狀態、輸入後狀態(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> //這是form中的數據格式 { nameGroup: { firstName: '', lastName: '' } }
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){ } }
.ng-valid[required] { border-left: 5px solid #0f0; } .ng-invalid { border-left: 5px solid #f00; } <p [hidden]="contactName.valid || contactName.pristine">用戶名長度爲3-10個字符</p>
表單內置檢驗: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: '用戶名必須是手機號或者郵箱帳號' } }; }
//... 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 {}
首先要導入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) }); }
分別定義了FormGroup和FormControl的實例化對象
Angular中,管道能夠按照開發者指定的規則將模板內的數據進行轉換。
模板中,經過管道操做符 | 使用管道,| 左邊的爲輸入數 據,右邊爲管道。管道能夠帶有參數,經過傳入參數輸出不一樣格式數據。同時,模板表達式中能夠同時使用多個管道進行不一樣的處理。
<p>{{ birthday | date }}</p> <P>{{ birthday | data:"MM/dd/y" }}</p> <p>{{ expression | pipeName1 | pipeName2 }}</p>
內置管道:Angular提供的,不需導入能夠直接使用。
expression | date: format expression | json expression | uppercase expression | lowercase expression | number[: digitInfo] expression | currency[: currencyCode[: symbolDisplay[: digitInfo]]] expression | percent expression | slice: start[: end]
自定義管道:經過如下幾個步驟實現
//sexreform.pipe.ts import { Pipe, PipeTransform } from "@angular/core"; @Pipe { name: 'sexReform' } export class SexReform implements PipeTransform { //... }
export class SexReform implements PipeTransform { transform(val: string): string { switch(val) { case 'male': return '男'; case 'female' return '女'; default: return '未知性別'; } } }
//使用管道前,須要在@NgModule的元數據declarations數組中添加自定義管道 import { SexReform } from 'pipes/sexreform.pipe'; @NgModule ({ //... declarations: [SexReform] }) //能夠像內置管道通常使用自定義管道咯 @Component ({ selector: 'pipe-demo-custom', template: ` <p>{{ sexValue | sexReform }}</p> ` })
純管道與非純管道的區別:只有發生純變纔會調用該管道,這類管道稱爲純管道,其他的管道成爲非純管道。純變指的是對基本數據類型(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); } }
初始日期分別爲:
'2016-06-08 20:05:08 Wednesday' '2016-06-08 20:05:08 Wednesday'
2s以後變成了
'2016-06-08 20:05:08 Wednesday' '2016-12-08 20:05:08 Thursday'