寫了幾節(jié)UI方面的內(nèi)容复唤,有點累了吧杂穷?這節(jié)先換點別的東西寫擎淤。
前面章節(jié)基本把應(yīng)用的總體配置完成了脑漫,開始進入具體頁面的開發(fā),而這些離不開與數(shù)據(jù)的交互袋坑、與用戶的反饋操作等仗处。正所謂“兵馬未動,糧草先行”,現(xiàn)在封裝下基本的服務(wù)婆誓。
前面章節(jié)我們都是用命令行來操作咒精,如ionic g page person
,現(xiàn)在開始會涉及到很多命令操作旷档,可能有些人會記不住命令,或者記不清關(guān)鍵字歇拆,可以像我這樣鞋屈,在IDE上裝上插件,我這用的是VS Code故觅,裝了插件后厂庇,src
目錄右鍵會出現(xiàn)Ionic Generate
的快捷菜單,點擊后彈出選擇界面输吏,輸入名稱即可自動創(chuàng)建权旷。
關(guān)于IDE插件的,可以查看我另一篇文章開發(fā)工具插件贯溅。
TypeScript中拄氯,public為默認(rèn)訪問級別,即外部可以訪問的它浅,所以如果想控制權(quán)限译柏,請手動添加private關(guān)鍵字。常規(guī)應(yīng)用姐霍,一般會有通用服務(wù)和具體業(yè)務(wù)服務(wù)鄙麦,而常用的通用服務(wù)有如下幾個:
一、全局設(shè)置服務(wù)
ionic g provider config
import { Injectable } from '@angular/core';
import { Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class ConfigProvider {
constructor() {
}
/**
* 獲取域名
* @param versionType 版本類型镊折,0:正式環(huán)境胯府,1:測試環(huán)境,2: 本地
*/
static getDomainInfo(versionType: number = 1): any{
let domain: string;
switch(versionType){
case 0: domain = "http://"; break; //正式環(huán)境
case 1: domain = "http://"; break; //測試環(huán)境
case 2: domain = ""; break; //本地
default: domain = ""; break;
}
return {domain: domain, versionType: versionType};
}
/**
*獲取api地址
*/
static getApiHost(){
return ConfigProvider.getDomainInfo().domain + "";
}
static defaultHeaders = new Headers({'Content-Type': 'application/json', 'Accept': 'application/json'});
static formHeaders = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json'});
static uploadHeasers = new Headers({'Content-Type': 'multipart/form-data'});
//
static defaultOptions = new RequestOptions({headers: ConfigProvider.defaultHeaders});
static formOptions = new RequestOptions({headers: ConfigProvider.formHeaders});
static uploadOptions = new RequestOptions({headers: ConfigProvider.uploadHeasers});
}
因為有時需要在幾個環(huán)境切換服務(wù)地址恨胚,所以寫一個方法方便切換地址骂因;
另外angular默認(rèn)使用application/json的請求頭,有時我們需要根據(jù)后臺接口來配置請求頭与纽,在這就預(yù)先配置幾個常用的RequestOption侣签,方便按需要隨時切換。
二急迂、網(wǎng)絡(luò)請求服務(wù)
ionic g provider common
import 'rxjs/add/operator/retry';
import 'rxjs/add/operator/timeout';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import { Headers, Http, RequestOptions } from '@angular/http';
import { ConfigProvider } from './config';
import { Injectable } from '@angular/core';
//處理過的響應(yīng)數(shù)據(jù)
export interface IResponseData<T> {
success: boolean;
msg: string;
code?: number;
result?: T; //響應(yīng)數(shù)據(jù)
}
@Injectable()
export class CommonProvider {
constructor(public authHttp: Http) {
}
/**
* get方法(isJoinHost是為了兼容獲取應(yīng)用內(nèi)部數(shù)據(jù))
* @param url 請求url
* @param isJoinHost 是否合并到主機地址
*/
get(url: string, isJoinHost: boolean = true) {
url = (isJoinHost && url.indexOf('http') <0) ? ConfigProvider.getApiHost() + encodeURI(url) : encodeURI(url);
return this.authHttp.get(url)
.timeout(60000)
.toPromise()
.then(result => result.json())
.catch(resp => this.handleHttpError(resp));
}
/**
* post方法
* @param url 請求url
* @param data 請求參數(shù)
* @param options 請求選項
*/
post(url: string, data: any = {}, options: RequestOptions = ConfigProvider.formOptions) {
url = url.indexOf('http') > -1 ? url : ConfigProvider.getApiHost() + url;
return this.authHttp.post(url, data, options)
.timeout(60000)
.toPromise()
.then(result => result.json())
.catch(resp => this.handleHttpError(resp));
}
/**
* 處理http錯誤
*/
handleHttpError(resp): IResponseData<any> {
let errMsg = '抱歉影所,后臺服務(wù)出錯了';
if (resp) {
let msg: string = resp.message;
if (msg && msg.toLowerCase().indexOf('timeout') > -1) {
errMsg = '請求超時,請稍后重試僚碎!';
} else {
switch (resp.status) {
case 401: errMsg = '無權(quán)限訪問猴娩,或許登錄信息已過期,請重新登錄';
case 404: errMsg = '抱歉,后臺服務(wù)找不到對應(yīng)接口';
case 0: errMsg = '網(wǎng)絡(luò)無法連接';
default: break;
}
}
}
return { success: false, msg: errMsg, code: -1, result: null};
}
}
這里只簡單的封裝了帶超時和錯誤處理的get卷中、post方法矛双。因為數(shù)據(jù)接口服務(wù)往往不會只返回數(shù)據(jù),還應(yīng)帶有請求信息蟆豫,如獲取數(shù)據(jù)為空议忽,可以提示是系統(tǒng)問題、權(quán)限問題還是數(shù)據(jù)本就這樣十减,所以封裝了統(tǒng)一響應(yīng)數(shù)據(jù)接口栈幸。
因為目前大多插件的異步使用Promise,Observable轉(zhuǎn)Promise比較簡單帮辟,而Promise轉(zhuǎn)Observable比較麻煩速址,為了更方便集成,所以把官方推薦的Observable方式轉(zhuǎn)成Promise方式由驹,大家可基于Observable優(yōu)點考慮仍沿用Observable也行芍锚。
注意catch里面用了return,表示捕獲了異常處理并返回蔓榄,下次鏈?zhǔn)秸{(diào)用將進入then并炮,這樣每個調(diào)用網(wǎng)絡(luò)請求后的邏輯操作可以全放在then里,省掉寫catch的部分润樱。要想下次鏈?zhǔn)秸{(diào)用再處理異常渣触,就應(yīng)用Promise.reject繼續(xù)拋出異常。
三壹若、權(quán)限服務(wù)
ionic g provider auth
先建個文件備用嗅钻。
四、緩存服務(wù)
ionic g provider cache
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Storage } from '@ionic/storage';
/**
* 用枚舉管理key值店展,防止字符串拼錯
*/
export enum CacheKeys {
TOKEN, AUTO_LOGIN, USER_INFO
}
@Injectable()
export class CacheProvider {
constructor(public http: Http, public storage: Storage) {
console.log(CacheKeys[CacheKeys.TOKEN]);
}
}
因為key使用字符串方式养篓,不容易記憶使用,也容易敲錯赂蕴,為了便于管理Key柳弄,用枚舉來處理。后續(xù)補充結(jié)合http的緩存請求概说。
五碧注、工具服務(wù)
ionic g provider util
import 'rxjs/add/operator/map';
import { DomSanitizer } from '@angular/platform-browser';
import { Injectable } from '@angular/core';
/*
工具類
Generated class for the UtilProvider provider.
*/
@Injectable()
export class UtilProvider {
constructor(private sanitizer: DomSanitizer) {
}
/**
* 深拷貝
*/
deepCopy(originObj: any): any{
return originObj ? JSON.parse(JSON.stringify(originObj)) : null;
}
/**
* 處理html的安全信任
* @param html raw html
*/
sanitizeHtml(html: string): any{
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}
先實現(xiàn)兩個應(yīng)該要用到的方法,待后續(xù)實現(xiàn)功能時再擴展糖赔。
這些服務(wù)會隨著業(yè)務(wù)功能的開發(fā)而補充萍丐,服務(wù)的每個方法可以不寫返回類型(如fun: Promise<any>里的
Promise<any>
),但為了肉眼快速分辨出是異步方法還是普通方法放典?返回參數(shù)是什么類型逝变?我習(xí)慣了書寫基茵。
晚了,先寫到這里壳影。