簡述:組件(component)是構成Angular應用的基礎和核心.能夠這樣說,組件用來包裝特定的功能,應用程序的有序運行依賴於組件之間的協同工做.css
1. 組件化標準:W3C爲了統一組件化的標準方式,提出了Web Component的標準.經過標準化的非侵入方式封裝組件,每一個組件包含本身的HTML,CSS,JavaScript代碼,
而且不會對頁面上其餘組件產生影響.Web Component是由一些新技術構成的,還提供了瀏覽器原聲的UI組件標準,因此不須要引入任何外部的依賴.要使用一個已有的
Web Component組件,僅需以下添加一行導入聲明,如:
<link rel="import" href="xxxxx.html" />
Web Component標準包括以下四個重要的概念:
1.自定義元素:這個特性容許建立自定義的HTML標記和元素,每一個元素都有屬於本身的腳本和樣式.
2.模板:模板容許使用<template>標籤去預先定義一些內容,但並不隨頁面加載而渲染,而是能夠在運行時使用JavaScript去初始化它.
3.Shadow DOM:經過Shadow DOM能夠在文檔流中建立一些徹底獨立於其餘元素的DOM子樹,這個特性可讓開發者開發一個獨立的組件,而且不會干擾到其餘DOM元素.
4.HTML導入:一種在HTML文檔中引入其餘HTML文檔的方法,用於導入Web Component的機制.
注意:目前僅有Chrome瀏覽器對該標準支持最高,其餘主流瀏覽器並未徹底實現Web Component標準.
有關Web Component標準的更多信息可待之後研究,這裏並不深究.html
2. Angular組件:在Angular中引入了視圖包裝(ViewEncapsulation)的概念,容許經過設置ViewEncapsulation.Native選項來使用原生的Shadow DOM.Angular還支持模板,
自定義標籤,異步加載組件等.Angular組件是自描述的--能夠和宿主元素交互,知道如何以及合適渲染本身,可配置注入服務,有明確的Input和Output定義.全部Angular的組件均可以
獨立存在,均可以做爲根組件被引導,也能夠被路由加載,或者在其餘組件中使用.不過一個組件不能單獨被啓用,它必須被包裝到模塊(NgModule)中.
組件是Angular應用的最小的邏輯單元,模塊則是在組件之上的一層抽象.組件以及其餘部件,如指令,管道,服務,路由等均可以被包含到一個模塊中.外部引用經過引用這個模塊來使用
一系列封裝好的功能.bootstrap
3. 建立組件的步驟:
1.從@angular/core中引入Component裝飾器.
2.創建一個普通的類,並用@Component修飾它.
3.在@Component中,設置selector自定義標籤和template模板.數組
4. 組件裝飾器:@Component是TypeScript的語法,它是一個裝飾器,任何一個Angular組件類都會用這個裝飾器修飾,組件類最終編譯成的JavaScript代碼以下:
var ContactItemComponent=(function(){
function ContactItemComponent(){};
ContactItemComponent=__decorate([core_1.Component({
selector:'contact-item',
template:`
<div>
<p>xzm</p>
<p>13648301556</p>
</div>
`
})__metadata(`design:paramtypes`,[])
],ContactItemComponent);
return ContactItemComponent;
}());
其中,Angular的@Component會被轉換成一個__decorate()方法,元數據的定義經過core_1.Component傳入,將ComtactItemComponent這個類裝飾器來,使得
ContactItemComponent具備裝飾器裏定義的元數據屬性.瀏覽器
5. 組件元數據:
5.1 selector:是用於定義組件在HTML代碼中匹配的標籤,它將稱爲組件的命名標記.一般狀況下都須要設置selector,特俗狀況能夠忽略,不指定時設置默認爲匹配div元素.
selector的命名方式建議使用"烤肉串式"命名,即採用小寫字母並以-分隔.
5.2 template是爲組件指定一個內聯模板.內聯模板建議使用ES6的多行字符串``(兩個反引號),這樣可建立多行.
5.3 templateUrl:是爲組件指定一個外部模板的URL地址.
5.4 styles:是爲組件制定內聯樣式,如:
@Component({
styles:[`
li:last-child{
border-bottom:none;
}
`]
})
5.5 styleUrls:是爲組件指定一系列用於該組件的外聯樣式表文件,如:
@Component({
styleUrls:['app/list/item.component.css']
})
注意:styles和styleUrls容許同時指定.同時指定,styles中的樣式會被先解析,也就是styles的樣式會被styleUrls的覆蓋.app
6. 模板:每一個組件都必須設置一個模板,angular才能將組件內容渲染到DOM上,這個DOM元素就是宿主元素.組件能夠與宿主元素交互,交互的形式以下:
1.顯示數據
2.雙向數據綁定
3.監聽宿主元素事件以及調用組件方法.
6.1 顯示數據:可使用插值語法{{}}來顯示組件的數據.
6.2 雙向數據綁定,使用[(ngModule)]='property'的語法.
6.3監聽宿主元素事件及調用組件方法:()是Angular提供的事件綁定語法糖,經過(eventName)的方式能夠輕易地響應UI事件.框架
7. 組件和模塊:Angular提供了@NgModule裝飾器來建立模塊,一個應用能夠有多個模塊,但只有一個根模塊(RootModule),其餘模塊叫做特性模塊(FeatureModule).根模塊是啓動應用
的入口模塊,根模塊必須經過bootstrap元數據來指定應用的根組件,而後經過bootstrapModule()方法來啓動應用.
7.1 NgModule主要的元素居以下:
1.declarations:用於指定屬於這個模塊的是視圖類(View Class),即指定那些部件組成了這個模塊.Angular又組件,指令和管道三種視圖類,這些視圖類只能屬於一個模塊,必須
注意不能再次聲明屬於其餘模塊的類.
2.exports:導出視圖類.當該模塊被引入到外部模塊時,這個屬性指定了外部模塊可使用該模塊的那些視圖類,因此它的值類型跟declarations一致.
3.imports:引入該模塊依賴的其餘模塊或路由,引入後模塊裏的組件模板才能引用外部對應的組件,指令和管道.
4.providers:指定模塊依賴的服務,引入後該模塊中的全部組件均可以使用這些服務.
7.2 導出視圖類以及導入依賴模塊:有時候模塊中的組件,指令或管道,可能也會在其餘模塊中使用,這時可使用exports元數據對外暴露這些組件,指令或管道.而相對應的,若是在一個模塊
中想要使用其餘模塊對外暴露的組件,服務等,除了須要在模塊的文件頭使用import from導入模塊,同時還要在NgModule的元數據import中爲該模塊制定要導入的依賴模塊,這其中的
兩個導入(import),前一個是TypeScript的模塊導入,後一個是Angular框架的模塊導入,但願這裏不要混淆了.
7.3 服務引入:
引入服務有兩種方式:
1.經過@NgModule的providers引入,經過它引入的服務,在模塊的全部組件均可以使用.
2.經過@Component的providers引入,經過它引入的服務,在組件及其子組件中均可以共用這些引入的服務.異步
8. 組件交互:組件交互就是組件經過必定的方式來訪問其餘組件的屬性或方法,從而實現數據的雙向流通.組件交互有不少種方式,非父子關係的組件可經過服務來實現數據交互通訊.
8.1 組件的輸入輸出屬性:Angular除了提供@Input和@Output裝飾器語法來處理組件數據的流入流出外,還提共了在組件的元數據中使用inputs,outputs來設置輸入輸出屬性,設置的值必須
爲字符串數組,元素的名稱須要和成員變量相對應.
如:
@Component({
inputs:['contact'], //'contact' 匹配成員變量contact
outputs['routerNavigate']
})
8.2 父組件向子組件傳遞數據:父組件的數據是經過子組件的輸入屬性流入子組件,在子組件完成接收或者攔截,從而實現了數據由上而下的傳遞.
Angular會從根組件開始啓動,並解析整棵組件樹,數據以由上而下的方式流向下一級子組件.不過須要注意的是,目標組件的屬性必須經過輸入屬性(@Input)明確的標記才能接收到來自
父組件的數據.
8.3 攔截輸入數據:子組件能夠攔截輸入屬性的數據並進行相應的處理.
有以下兩種方式:
1.setter攔截輸入屬性:getter和setter一般一塊兒使用,用來對屬性進行相關約束.它們提供了對屬性讀寫的封裝,使代碼結構更清晰,更具可擴展性.setter可對屬性進行再封裝
處理,對複雜的內部邏輯經過訪問權限控制來隔絕外部調用,以免外部的錯誤調用影響到內部的狀態.同時也要把內部複雜的邏輯結構封裝成高度抽象可被簡單調用的屬性,再經過
getter返回要設置的屬性值,方便調用者使用.
setter攔截器示例,如:
@Component({
selector:'list-item',
template:`
<div>
<label class='contact-name'>{{contactObj.name}}</label>
</div>
`
})
exports class ListItemComponent impl OnInit{
_contact:object={};
@Input
set contactObj(contact:object){
this.)contact.name=(contact.name && contact,name.trim()) || '名字爲空!';
}
get contactObj(){return this._contact;}
}
這裏經過settet的方式設置一個contactObj屬性對象,其做用是經過對@Input修飾符獲取的數據contact(父組件傳入的)進行二次處理,再經過getter返回這個contactObj對象.
2.ngOnChanges監聽數據變化:ngOnChanges用於及時響應Angular在屬性綁定中發生的數據變化,該方法接收一個對象參數,包含當前值和變化前的值.在ngOnInit以前,或者當數據
綁定的輸入值發生變化時會觸發.
ngOnChange方法接收一個參數,該參數類型是SimpleChanges類.它是Angular的一個基礎類,用於處理數據的先後變化,其中包含兩個重要成員,分別是previousValue和
currentValue,previousValue是獲取變化前的數據,而currentValue是獲取變化後的數據.
如:
//父組件代碼 detail.component.ts
import { Component } from '@angular/core';
@Component({
selector:'detail',
template:`
<a class='edit' (clikc)='editContact()'>編輯</a>
<change-log [contact]='detail'></changelog>
`
})
export class DetailComponent implements OnInit{
detail:any={};
//...此處省略給 detail獲取數據的代碼
//完成聯繫人編輯修改
editContact(){
//...
this.detail=data;
}
}
//子組件代碼 changelog.component.ts
import { Component,Input,Onchanges,SimpleChanges } from '@angular/core';
@Component({
selector:'change-log',
template:`
<h4>change log</h4>
<ul>
<li *ngFor="let change of changes">{{}change}</li>
</ul>
`
})
export clas ChangeLogComponent implements OnChanges{
@Input() contact:any={};
changes:string[]=[];
ngOnChange(changes:{[propKey:string]:SimpleChanges}){ // 有關{ [propKey:string]:SimpleChanges }代碼的解釋請看下面說明
let log:string[]=[];
for(let propName in changes){
let changeProp=changes[propName],
from =JSON.stringify(changeProp.previousValue),
to =JSON.stringify(changeProp.currentValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
this.changes.push(log.join(','));
}
}
注:上面代碼中又一行代碼{[propKey:string]:SimpleChanges},這是做爲一個TypeScript類來定義ngOnChanges方法的參數類型,那麼該代碼表明的是什麼類呢?
直接說,其實就是一個雙列集合,或者叫字典,如同Jave裏面的Map集合,C#裏面的Directory.而在TypeScript這裏,字典類的定義比較麻煩,屬於可索引類型接口,索引爲
字符串類型,也就是[propKey:stirng],其後":SimpleChanges"定義了該字典類型中的元素類型必須爲SimpleChanges類型,因爲TypeScript的字典是經過接口的語
法方式實現的,因此這裏最後又用了一對花括號把它包裹起來,這代表它是一個匿名的接口類型,也就是匿名的可索引接口類型.
8.4 子組件向父組件傳遞數據:使用事件傳遞是子組件向父組件傳遞數據最經常使用的方式.子組件須要實例化一個用來訂閱和觸發自定義事件的EventEmitter類,這個實例對象是一個由
裝飾器@Output修飾的輸出屬性,當有用戶操做行爲發生時該事件會被觸發,父組件則經過事件綁定的方式來訂閱來自子組件觸發的事件,即子組件觸發具體的事件(自定義)會被其父
組件訂閱到.
示例:
//父組件,收藏聯繫功能
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;
}
}
父組件CollectionComponent經過綁定自定義事件onCollect訂閱來自子組件觸發的事件.當有來自子組件對應的事件被觸發,在父組件中可以監聽到該事件.
注意:這裏的具體業務邏輯功能是在父組件的collectTheCOntact()中實現的.
示例:
//子組件
import { Component ,EventEmitter,Input,Output } from '@angular/core';
@Component({
selector:'contact-collect',
template:`<i [ngClass]='{ collected:contact.collecttion }' (click)='collectTheContact()'>收藏</i>`
})
export class ContactCollectComponent{
@Input() contact:any={};
@Output() onCollect=new EventEmitter<boolean>();
collectTheContact(){
this.onCollect.emit();
}
}
經過輸出屬性@Output將數據流向父組件,在父組件完成事件的監聽,以此來實現從子組件到父組件的數據交互.這個過程父組件數據流入子組件不太同樣,其實一個父組件主動流入方式,
子組件的數據是在一些特定的時候或者條件下,由子組件主動發起,父組件被動觸發(訂閱到)事件來的獲得子組件傳遞的數據.
8.5 經過局部變量實現數據交互:經過建立模板局部變量的方式,來實現父組件與子組件數據交互,即在父組件的模板中爲子組件建立一個局部變量,那麼這個父組件能夠經過這個局部來獲取
子組件公共成員變量和函數的權限.模板局部變量的做用域範圍僅存在於該模板局部變量的子組件.
示例代碼:
import { } from '@angular/core';
@Component({
selector:'collection',
template:`
<contact-collect (click)='collect.collectTheContact()' #collect></contact-collect>
`
})
export class CollectionComponent{}
在父組件模板中的子組件標籤上綁定一個局部變量,以#號標記,以此來獲取子組件類的實例對象.如上代碼#collect就是綁定子組件類的實例對象.
模板局部變量的方式是在子組件方法中實現具體的業務邏輯,和父組件訂閱子組件自定義事件的方式實現業務邏輯地方正好相反.
8.6 @ViewChild實現數據交互:使用模板變量只能在模板中使用,不能直接在父組件類裏使用,這又必定的侷限性.當父組件須要獲取子組件中的變量,方法的讀寫權限時,能夠經過@ViewChild
注入的方式來實現.
組件中元數據ViewChild的做用是聲明對子組件元素的實例引用,它提供了一個參數來選擇將要引用的組件元素,這個參數能夠是一個類的實例,也能夠是一個字符串.
1.參數爲類實例,表示父組件將綁定一個指令或者子組件實例.
2.參數爲字符串類型,表示將起到選擇器的做用,即至關於在父組件中綁定一個模板局部變量,獲取到子組件的一份實例對象的引用.
示例如:
import { } from '@angular/core';
@Component({
selector:'collection',
template:`
<contact-collect (click)='collectTheContact()'></contact-collect>
`
})
export class CollectionComponent{
@ViewChild(ContactCollectComponent) contactCollect:ContactCollectComponent; //子組件類變量ide
collectTheContact(){
this.contactCollect.collectTheContact();
}
}函數
9. 組件內容嵌入:內容嵌入(ng-content)是組件的一個高級功能特性,使用組件的內容嵌入特性能很好的擴從組件的功能,方便代碼的複用.內容嵌入一般用來建立可複用的組件,典型的例子
是模態對話框或導航欄.
示例如:
import { Component } from '@angular/core';
@Component({
selector:'example-content',
template:`
<div>
<h4>ng-content 示例</h4>
<div style="backgroud-color:gray;padding:5px;margin:2px;">
<ng-content selector="header"></ng-content>
</div>
</div>
`
})
export class NgContentExampleComponent{}
在上面代碼中,使用了<ng-content>標籤,這個標籤使用來渲染組件嵌入內容的.在<ng-content>中有個selector='header'屬性,用於匹配內容,並填充到ng-content中.
有了以上帶有內容嵌入的組件,那麼就能夠在以下的跟組件中使用該組件,例如:
import { Component } from '@angular/core';
@Component({
selector:'app',
template:`
<example-content>
<header>組件動態內容嵌入部分,能夠替換該組件中的ng-content標籤中的內容</header>
</example-content>
`
})
export class NgContengAppComponent{}
上面用到的selector是一個選擇器,與CSS選擇器相似,selector='header',表示匹配組件模板調用中<header>標籤,固然還有其餘的匹配方式,以下:
1.selector='.class-select' :經過標籤上的某個CSS類來匹配.
2.selector='[name=footer]' :經過標籤上的某個屬性值來匹配.
10. 組件的生命週期:組件的生命週期由Angular內部管理,從組件的建立,渲染,到數據變更事件的觸發,再到組件從DOM中移除,Angular都提供了一系列的鉤子. 10.1 生命週期的鉤子:開發者能夠實現一個或者多個生命週期鉤子(接口),從而在生命週期的各階段作出適當的處理.這些鉤子包含在@Angular/core中, 如下是組件經常使用的生命週期鉤子: 1.ngOnChanges:它是用來響應組件輸入值(經過@Input裝飾去顯式指定的變量)發生變化時觸發的事件,接收一個SimpleChanges對象,包含當前值和變化前值, 該方法在ngOnInit以前. 2.ngOnInit:用於數據綁定輸入性以後初始化組件,該鉤子方法會在第一次ngOnChanges以後被調用.使用ngOnInit有如下兩個重要緣由: a.組件構造後不久須要進行復雜的初始化. b.須要在輸入屬性設置完成以後才構建組件. 3.ngDoCheck:用於變化監測,該鉤子方法會在每次變化監測發生時被調用.每個變化監測週期內,無論數據值是否發生變化,ngDoCheck都會被調用,該方法須要慎用, 如鼠標移動觸發mousemove事件 4.ngAfterContentInit:在組件使用<ng-content>將外部內容嵌入到組件視圖後就會調用它,它在第一次ngDoCheck執行後調用,且只執行一次. 5.ngAfterContentChecked:在組件使用了<ng-content>自定義內容的狀況下,Angular在這些外部內容嵌入到組件視圖後,或者每次變化監測的時候都會調用 ngAfterContentChecked. 6.ngAfterViewInit:會在Angular建立了組件的視圖及其子組件視圖以後被調用. 7.ngAfterViewChecked:在Angular建立了組件的視圖及其子組件視圖以後被調用一次,而且在每次子組件變化監測時也會被調用. 8.ngOnDestroy:在銷燬指令/組件以前觸發.那些不會被垃圾回收器自動回收的資源都應當在ngOnDestory中手動銷燬.