敲代碼要有點逼格、要有點追求、
1.暴露問題
一般地,我們在vue項目中經常會用到vue-resource或者axios來進行網絡數據請求、剛接觸不久的同學會很自然的直接調用其api來進行請求,例如:

這種將url直接寫死的,直接拖出去打死吧、【如果服務地址發生變化,整個項目接口都需要去更改】

這種稍微好點的,知道將地址配成一個全局變量。【總感覺還是太過累贅,而且並不能直觀反應這段請求的目的是做什么的】
2.思考我們需要怎么做
理想狀況下,我們希望在需要調用接口的時候直接調用一個方法,傳入參數,然后拿到數據,類似這樣:

【方法名很直觀,沒有暴露出接口地址,代碼不會亂】
3.vue項目結構升級
a.這里我們將抽離出service來管理各個模塊的請求;
b.將抽離出一個文件api.js來統一管理請求接口的地址;
c.並將axios或者vue-resource的請求做一個封裝http.js,方便調用;
首先看一下完整結構:

先看一下http.js:
1 /** 2 * http utils, provide general check for http response 3 */ 4 5 axios.defaults.headers.post['Content-Type'] = 'application/json' 6 axios.defaults.withCredentials = true 7 8 axios.interceptors.request.use(function (config) { 9 // 動態設置參數 10 //config.headers = Object.assign(config.headers || {}, {accessToken: '63F5640A1FE54E22A53AA8879373CEB8'}) 11 12 // config.params = Object.assign(config.params || {}, {deviceType: 'wap'}) 13 14 return config 15 16 }, function (error) { 17 // Do something with request error 18 return Promise.reject(error) 19 }) 20 21 const getSettings= () => { 22 return axios.defaults // 返回 axios 配置對象供外部設置或自定義特殊處理 23 } 24 25 const checkHttp = (res) => { 26 if (!res) { 27 let errObj = { 28 message: '響應數據為空', 29 response: null 30 } 31 32 throw errObj 33 } 34 35 let status = res.status 36 if (status === 200) { 37 return res.data 38 } 39 40 let errObj = { 41 message: '請求錯誤', 42 response: res 43 } 44 45 throw errObj 46 } 47 48 const checkResult = (res) => { 49 let data = checkHttp(res) 50 var ua = navigator.userAgent.toLowerCase(); 51 if (data.retCode == '1000') { 52 53 return data 54 } 55 56 57 if (data.retCode == '2005'){ 58 if(ua.match(/MicroMessenger/i)=="micromessenger") { 59 60 window.location = "http://www.ucaigou.net/weixin/user/auth?autoCreateUserFlag=0&gotoUrl=http://mobile.ucaigou.net" 61 return 62 } else { 63 64 return 65 } 66 } 67 68 let errObj = { 69 message: data.retMsg || '請求錯誤', 70 response: res 71 } 72 73 throw errObj 74 } 75 76 export const get = (url, params, headers) => { 77 return axios.get(url, {params, headers}).then(checkResult) 78 } 79 80 export const post = (url, data, headers) => { 81 return axios.post(url, data, headers).then(checkResult) 82 } 83 84 export const formPost = (url, params) => { 85 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded' 86 let formData = "" 87 if(params) { 88 for (var key in params) { 89 formData += key + "=" + params[key] + "&" 90 } 91 } 92 return axios.post(url, formData).then(checkResult) 93 } 94 95 export const put = (url, data) => { 96 return axios.put(url, data).then(checkResult) 97 } 98 99 export const del = (url) => { 100 return axios.delete(url) 101 } 102 103 /** 104 * raw json request 105 */ 106 export const getJson = (url, params) => { 107 return axios.get(url, params).then(checkHttp) 108 } 109 110 export default {get, post,formPost, put, del, getJson, getSettings}
【這段代碼可以提出來公用,其實也就是對axios的各種方法進行提取封裝】
看看api.js文件:
4 import {devMode} from 'utils/env' 5 const DEFAULT_API_BASE = devMode ? '/' : '//www.xxxxxx.net/' 6 7 const _dataPath = (url) => { 8 return `${DEFAULT_API_BASE}/${url}` 9 } 10 11 /** 12 * API請求參數和響應內容的具體說明可參考 13 * 14 */ 15 export default { 16 PROV_CITY_DICT: _dataPath('api/provCityDist'), // 省市區查詢 17 TOWN_DICT: _dataPath('api/town'), // 區縣(四級地址)查詢 18 CATEGORY_LIST: _dataPath('api/product/category'), // 商品分類查詢 19 PRODUCT_LIST: _dataPath('api/product/list'), // 商品列表查詢 20 PRODUCT_DETAIL: _dataPath('api/product/detail'), // 商品詳情查詢 21 HOME_BANNER_LIST: _dataPath('api/home/banner/list'), // banner位 22 HOME_SCENE_LIST: _dataPath('api/home/scene/list'), // 場景采購(高校采購場景方案) 23 HOME_FLOOR_LIST: _dataPath('api/home/floor/list'), // 樓層數據 24 RECOMMEND_PRODUCT_LIST:_dataPath('api/product/recommend'), // 推薦商品列表 25 PRODUCT_KEYWORD_SUGGEST:_dataPath('api/product/suggest'), // 商品關鍵詞聯想 26 ADDR_ADD: _dataPath('api/address/add'), // 用戶地址添加 27 ADDR_DEL: _dataPath('api/address/delete'), // 用戶地址刪除 28 ADDR_UPDATE: _dataPath('api/address/update'), // 用戶地址更新 29 ADDR_LIST: _dataPath('api/address/list'), // 用戶全部地址查詢 30 ADDR_QUERY: _dataPath('api/address/query'), // 用戶地址查詢 31 ADDR_DEFAULT: _dataPath('api/address/default'), // 獲取用戶默認收貨地址 32 CART_ADD: _dataPath('api/shoppingCart/add'), // 購物車添加 33 CART_QUERY: _dataPath('api/shoppingCart/query'), // 購物車列表查詢 34 CART_UPDATE: _dataPath('api/shoppingCart/update'), // 購物車更新數量 35 CART_DEL: _dataPath('api/shoppingCart/delete'), // 購物車刪除 36 ......... 37 38 39 }
【這段代碼將項目中用到的所有接口地址全部進行了配置】
接下來看看service文件:
1 import http from 'utils/http' 2 import api from 'api' 3 4 5 /** 6 * 訂單列表 7 */ 8 9 10 export const orderList = async (params) => { 11 const sendParams = Object.assign({ // 默認參數 12 "pageNum": 1, 13 "pageSize": 15, 14 }, params) 15 16 return http.post(api.ORDER_LIST, sendParams) 17 } 18 19 20 /** 21 * 訂單詳情 22 */ 23 24 export const orderDetail = async (params) => { 25 return http.get(`${api.ORDER_DETAIL}?id=${params}`) 26 } 27 28 29 /** 30 * 查看物流 31 */ 32 33 export const orderEpress = (params) => { 34 return http.post(api.ORDER_EXPRESS, params) 35 }
【導入http.js、api.js,可以看到每一個service方法都返回一個promise對象】
使用方法:
import {orderList,cancleOrder,orderRecevce} from 'services/order.service'
【使用時導入需要用到的方法,並調用】

完結、
