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'

【使用时导入需要用到的方法,并调用】

完结、

 

posted @ 2018-07-10 15:19  IT民工梅西布莱恩特  阅读(1995)  评论(1编辑  收藏  举报