ionic3開(kāi)發(fā)框架是angular4,所以了解一下angular4的一些基礎(chǔ)知識(shí),能讓你更好的開(kāi)發(fā)應(yīng)用。
angular4提供了很多功能強(qiáng)大的內(nèi)置指令,但在現(xiàn)實(shí)情況中,這些內(nèi)置指令可能還不能完全滿足實(shí)際要求,這時(shí)我們就需要編寫(xiě)自定義指令來(lái)實(shí)現(xiàn)特定要求。
其實(shí)ionic3(angualr4)和ionic2(angular2)差不多,但和ionic1(angular1)就差別非常大了,可以說(shuō)基本是推倒了重來(lái)。在angular1時(shí)代,組件和指令是一回事,即嚴(yán)格來(lái)說(shuō),沒(méi)有組件這概念,只有指令,而到了angular2時(shí)代,雖說(shuō)組件仍是一種特殊的指令,但已經(jīng)有一定目的明顯區(qū)分開(kāi)來(lái),分別用Directive和Component來(lái)標(biāo)識(shí),用cli生成命令就如下所示:
ionic g directive 指令名
ionic g component 組件名
要說(shuō)指令和組件的區(qū)別,簡(jiǎn)單說(shuō)是不帶視圖和帶視圖的區(qū)別,直觀效果是:一個(gè)為原有標(biāo)簽動(dòng)態(tài)添加功能,另一個(gè)為新建自定義功能標(biāo)簽,詳細(xì)上有不少細(xì)節(jié)上的不同。
往往很多人會(huì)封裝組件,但不會(huì)去封裝指令,而選擇用Provider或者Pipe(管道,相當(dāng)于angular1時(shí)的過(guò)濾器filter),甚至樣式來(lái)實(shí)現(xiàn),雖說(shuō)這也能解決部分問(wèn)題,但不是最優(yōu)的,Directive、Componet、Provider、Pipe都有其專(zhuān)業(yè)適用場(chǎng)景,如結(jié)構(gòu)性指令(下面會(huì)說(shuō)),就不好用Provider和Pipe來(lái)處理。
Directive——指令
三種分類(lèi):
屬性指令
屬性指令指的是以屬性形式使用的指令,如ngModel、ngClass、ngStyle等。結(jié)構(gòu)指令
結(jié)構(gòu)指令,用于修改DOM結(jié)構(gòu)。其實(shí)就是模版指令,如ngIf,當(dāng)條件為true時(shí),該元素會(huì)被添加到DOM中。其主要依賴(lài)TemplateRef和ViewContainerRef來(lái)完成操作。TemplateRef用來(lái)訪問(wèn)組件的模板,而ViewContainerRef可作為視圖內(nèi)容渲染器,將模板內(nèi)容插入至DOM中。組件
這個(gè)不必說(shuō)了,我們用得最多的便是組件。與其他指令不同,它描述的是一個(gè)視圖,是用戶可以直接看到的東西。
自定義屬性指令
實(shí)例:創(chuàng)建一個(gè)bgColor屬性指令,支持傳入顏色名參數(shù),設(shè)置目標(biāo)標(biāo)簽的背景色
1)創(chuàng)建指令。cli使用如下命令創(chuàng)建基本指令,會(huì)生成bg-color.ts文件:
ionic g directive bgColor
2)修改指令。在構(gòu)造函數(shù)constructor加上一句,賦值默認(rèn)顏色:
import { Directive, Input, ElementRef } from '@angular/core';
@Directive({
selector: '[bg-color]' // Attribute selector
})
export class BgColorDirective {
constructor(private el: ElementRef) {
this.el.nativeElement.style.backgroundColor = 'red';
}
}
基于安全性考慮,angualr2的文檔是建議用Renderer來(lái)代替ElementRef使用,有興趣的可以自行了解下Renderer
3)使用指令
如果調(diào)用的頁(yè)面用了懶加載,在調(diào)用指令的頁(yè)面module.ts里導(dǎo)入指令并聲明,反之,在app.module.ts里導(dǎo)入指令并聲明,這樣調(diào)用的組件就能識(shí)別該指令了:
import { BgColorDirective } from '../../directives/bg-color/bg-color';
@NgModule({
declarations: [
ContactPage,
BgColorDirective
],
...
})
在ContactPage.html里這樣使用即可查看效果:
<button ion-button bg-color>
test
</button>

4)指令擴(kuò)展,支持輸入?yún)?shù)。
上述指令是一個(gè)很簡(jiǎn)單的指令,且很不靈活,因?yàn)轭伾珜?xiě)死為red了,實(shí)際上我們使用場(chǎng)景應(yīng)該支持多種顏色。那我們這樣修改:
import { Directive, Input, ElementRef } from '@angular/core';
@Directive({
selector: '[bg-color]' // Attribute selector
})
export class BgColorDirective {
defaultColor: string = 'red'; //默認(rèn)顏色
@Input('bg-color')
set backgroundColor(color:string) {
this.setStyle(color);
};
constructor(private el: ElementRef) {
this.setStyle(this.defaultColor);
}
private setStyle(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
改動(dòng)的只是用@Input裝飾器修飾,然后用set方法觸發(fā)獲得值后的操作。
我們?cè)诮M件html里就可以這樣調(diào)用了:
<button ion-button bg-color="green">
test
</button>

5)指令擴(kuò)展,支持事件操作
我們?cè)黾右粋€(gè)點(diǎn)擊事件響應(yīng)操作,點(diǎn)擊時(shí),循環(huán)切換背景色。為實(shí)現(xiàn)該功能,我們需要在事件處理函數(shù)上添加@HostListener裝飾器,代碼改動(dòng)如下:
import { Directive, Input, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[bg-color]' // Attribute selector
})
export class BgColorDirective {
defaultColor: string = 'red'; //默認(rèn)顏色
bgColor: string; //背景顏色
@Input('bg-color')
set backgroundColor(color:string) {
this.setStyle(color);
this.bgColor = color;
};
constructor(private el: ElementRef) {
this.setStyle(this.defaultColor);
}
private setStyle(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
@HostListener('click')
onClick() {
let color: string = this.el.nativeElement.style.backgroundColor == this.defaultColor ? this.bgColor : this.defaultColor;
this.setStyle(color);
}
}
效果圖為:我懶得做gif,你想象一個(gè)點(diǎn)擊循環(huán)切換背景色的按鈕吧。
自定義結(jié)構(gòu)指令
實(shí)例:山寨一個(gè)*ngIf的的收縮顯示指令,僅為了起到拋磚引玉效果。
為實(shí)現(xiàn)該指令,要借用TemplateRef和ViewContainerRef,TemplateRef用來(lái)訪問(wèn)組件的模板,而ViewContainerRef可作為視圖內(nèi)容渲染器,將模板內(nèi)容插入至DOM中。
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[expand]' // Attribute selector
})
export class ExpandDirective {
@Input('expand')
set condition(newCondition:boolean) {
if(!newCondition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
constructor(private templateRef: TemplateRef<any>, private viewContainer:ViewContainerRef) {
}
}
同樣別忘了在module里引入后,再在html里使用:
<div *expand="isExpand">
<button ion-button>test</button>
</div>
<div *expand="!isExpand">
一段文字
</div>
效果圖不上了,留待你們?cè)囼?yàn),哇咔咔。
Component——組件
ionic g component ContentEmpty
關(guān)于component,太多文章講了,這里我不詳細(xì)說(shuō)明,主要就兩個(gè)裝飾器:@Input、@Output,分別用于屬性和事件綁定。對(duì)于事件,使用EventEmitter發(fā)送參數(shù)即可。直接上代碼:
組件ts部分:
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'content-empty',
templateUrl: 'content-empty.html'
})
export class ContentEmptyComponent {
@Input() btnWorkText: string = ''; //加載成功后按鈕文字
@Output() doWork: EventEmitter<any> = new EventEmitter();
constructor() {
}
onDoWork($event){
this.doWork.emit($event);
}
}
組件html部分:
<button ion-button *ngIf="btnWorkText" color="blue" round outline small (click)="onDoWork($event)" >
{{btnWorkText}}
</button>
同樣在module里引入后,在html如下調(diào)用即可:
<content-empty [btnWorkText]="數(shù)據(jù)加載中" (doWork)="方法()"></content-empty>
總結(jié):可以看出來(lái),自定義指令和組件不算復(fù)雜,只是大家都沒(méi)有要去封裝的概念。如果幾乎不需要復(fù)用的東西,直接用內(nèi)置指令實(shí)現(xiàn)就好了,否則就要考慮自定指令了,能讓你的項(xiàng)目結(jié)構(gòu)更清晰化,至于選擇哪種,自己靜下心來(lái)想一下就好了。