前端系統開發中,因爲功能的複雜性後臺的數據接口會不少,若是每一個請求都寫在相應的頁面中維護起來特別繁瑣,因此就須要一個統一管理API的地方,已達到快速定位,這時候就須要請求與API模塊相關聯,以實現相應的操做。前端
項目中使用的ajax請求庫是axios,關於axios配置及攔截就不在這複述,網上例子不少,直接上二次封裝的代碼ios
import API from './api'; //存放API的模塊
import axios from '@/config/axios'
import {Message} from 'element-ui'
import {merge,path,isArray} from '@/assets/js/tool' //自定義封裝的輔助函數工具
const placeholder=/\{(\w+)\}?/gi; //佔位符
export class Fetch {
constructor(baseURL){
this.baseURL=baseURL || '/api';
this.headers=axios.defaults.headers;
}
//這裏是提交請求的入口,返回一個promiss
commit(url,payload,showMes){
const req= path(isArray(url)?url:[url],API);
const isShowMes=arguments.length===3 && Array.prototype.slice.call(arguments).pop();
const urlPath= payload && payload.path?this.buildPath(req.url,payload.path):req.url;
return new Promise((resolve,reject)=>{
axios({
url:this.baseURL.concat(urlPath),
method:req.method.toLowerCase(),
headers:this.headers,
data:payload.data || null,
params:payload.params || null,
timeout:5000
}).then(res=>{
const isError=this.creatErrorMes(res.data);
if(isError){
Message({message:res.data.msg,type:'error'});
}else{
isShowMes ? Message(this.makeMessage(res.data)):false;
resolve(res.data);
}
})
})
}
//這裏只是簡單的用了一下axios的header
setHeader(config){
this.headers=merge(this.headers,config)
}
//解析相似 /api/page/2這樣動態參數的問題,用正則去匹配咱們的佔位符,把真實數據放進去
buildPath(url,path){
if(!path)return url;
return url.replace(placeholder,function ($1,$2) {
return $2=encodeURIComponent(path[$2]);
});
}
// 解析對象爲params字符串,以便放入query中,考慮axios請求封裝了get的參數,這裏沒用到
buildUrlParams(url,params){
if(!params)return url;
let p=[];
Object.keys(params).forEach(key=>{
p.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`);
});
return url += (url.indexOf('?') === -1 ? '?' : '') + p.join('&');
}
// 統一設置前端接受數據或操做接口成功會給出的提示
makeMessage(data){
const mes={
message:data.message || "執行成功",
type:'success'
};
if(data.data && (!Object.keys(data.data).length || !data.data.length )){
mes.mesasge='暫無數據';
mes.type='warning';
return mes;
};
return mes
}
//建立收集後臺代碼錯誤信息並返回,有錯誤直接返回true
creatErrorMes(data){
// 收集後臺出錯的常見字段
const error=['code','msg'].every(item=>data.hasOwnProperty(item));
if(!Array.isArray(data)
&& typeof data ==='object'
&& data!==null
&& error){
return true;
};
return false
}
}
//以插件的形式封裝,掛載到Vue中
export function plugin(Vue,fetch){
if(plugin.installed){
return
};
plugin.installed=true;
Vue.fetch=fetch;
Object.defineProperties(Vue.prototype, {
fetch: {
get() {
return fetch
}
},
})
}
複製代碼
接下來在看一下API模塊就簡單了,能夠按照頁面或功能分類去管理接口ajax
export default {
login:{
url:'/xxxx/token',
method:'post',
},
user:{
info:{
url:'/xxx/info',
method:'get'
},
page:{
url:'/xxx/page/{num}'
method:'get'
}
}
}
複製代碼
項目中使用封裝的請求能夠這樣element-ui
Vue.use(plugin,new Fetch());
複製代碼
這裏展現的是請求API對象的一級鍵值axios
this.fetch.commit('login',{
data:{
username:'xxx',
password:'xxx'
}
}).then(res=>{
//do something
})
複製代碼
若是想請求相似接口中user的深層嵌套,能夠這樣api
//這裏封裝了prop方法以方便獲取更深層的對象
this.fetch.commit(['user','info'],{
params:{
id:'56',
}
},true)// 請求成功後會給出相應的提示
.then(res=>{
//do something
})
複製代碼
再來一個參數放在path的bash
// 執行完之後完整的url爲:'/xxx/page/1'
this.fetch.commit(['user','page'],{
path:{
num:'1',//這裏是佔位符相應的字段
},
params:{
.... //附帶的參數請求
}
})
.then(res=>{
//do something
})
複製代碼
基本思路就是這樣,其實還有不少能夠抽離優化的地方,也有不少設計不滿意的,不過如今基本能夠知足平常開發,後期會不斷優化。函數