vue优化项目结构之service请求篇
敲代码要有点逼格、要有点追求、
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'
【使用时导入需要用到的方法,并调用】
完结、
联系作者:
VX:Mm_Lewis