zoukankan      html  css  js  c++  java
  • Vue + webpack 项目配置化、接口请求统一管理

    准备工作

    需求由来: 当项目越来越大的时候提高项目运行编译速度、压缩代码体积、项目维护、bug修复......等等成为不得不考虑而且不得不做的问题。

          又或者后面其他同事接手你的模块,或者改你的bug时避免人家看的眼痛以及心里千百句mamaipi...问候。

          并且一个好的开发思路也能大大提高开发效率,以及检验自己。

    进入正题:

    在本地用 vue-cli 新建一个项目,这个步骤vue的官网上有,我就不再说了。

    这里展示一下我的项目架构目录  这次主要讲红字具体实现部分

          ├── build                       // 项目build脚本
          ├── config                      // 项目配置目录
          ├── dist                        // 项目输出部署目录,执行 npm run build后生成
          ├── src                         // 生产目录
          │   ├── assets                  // 静态资源,包含图片等
          │   ├── components              // 项目公用组件,例如Header、Footer组件等
          │   ├── mock                    // 接口mock文件目录
          │       └── index.js            // mock接口集合文件
          │   ├── pages                   // 页面目录
          │   │   ├── Demo                // Demo模块,必须用大写开头
          │   │   │   ├── components      // Demo模块专用组件 组件建议全部首字母大写
          │   │   │   ├── style           // Demo模块专用css
          │   │   │   ├── services        // Demo模块服务,可以包含相应方法类
          │   │   │   ├── interface.js    // Demo模块接口结合文件
          │   │   │   └── index.vue       // Demo模块页面入口
          │   │   └── Other               // 其他页面目录
          │   ├── router                  // 路由配置文件,如果路由太多了,可以拆分
          │   ├── services                // 项目公用配置服务
          │   │   │   ├── ajax.js         // 所有接口请求公共配置   可以和 request.js 合并一起 不嫌代码太长的话
          │   │   │   ├── request.js      // (需求有则添加) 为所有接口设置公共请求头
          │   │   │   ├── prompt.js       // 全局的提示  例如:接口错误提示、保存成功提示、操作错误提示等等...
          │   │   │   ├── validate.js     // 全局表单校验具体封装可参照element-ui form表单模块
          │   ├── App.vue                 // 组件入口
          │   ├── config.js               // 项目配置文件  例如:权限校验,cookie设置、access_token获取等等...
          │   ├── interface.js            // 项目公共接口文件
          │   └── main.js                 // Webpack 预编译主入口
          ├── style                       // 项目公用style
          ├── static                      // 静态文件目录,保留
          │   └── i18n                    // 国际化目录,每一个目录为一种语言
          │       ├── zh                  // 中文目录
          │       │   └── index.json      // 配置文件
          │       └── en                  // 英文目录
          ├── index.html                  // 项目入口文件,一般不用改动
          ├── package.json                // 项目配置
          ├── README.md                   // 项目说明
          ├── CHANGE_LOG.md               // 项目更新历史文档
          └── test                        // 测试目录

    services/aiax.js文件

    /**
     * ajax 模块,可以将 axios 替换成 $.ajax 等
     */
    import axios from 'axios';
    import globalConfig from '../config'
    import { Notification } from 'element-ui'
    
    // 注: 具体设置具体判断 根据公司项目需求 以及 接口需求   现在以我公司为例
    
    const init = function () {
      // 添加 axios 请求拦截器为所有请求加上前缀 、 access_token  (我公司所有接口都比要有 access_token才能访问)
      // 有对 axios 不是很了解的 可以看看 axios 官方文档  https://www.kancloud.cn/yunye/axios/234845
      axios.interceptors.request.use(function (config) {
        // 为所有接口加上前缀 例 https://www.kancloud.cn/yunye/axios/234845 前缀为 https://www.kancloud.cn
        // 因为相同环境下的所有接口前缀肯定是一样的 window.localStorage.gatewayDomain 为前缀域名  倘若后面更改域名之类的  只需改一个地方就行了 就不用说每个调接口的地方都去改  维护便捷
        // 若想了解分环境打包以及分环境设置 公共域名、前缀等  请看以往博文 https://www.cnblogs.com/ljx20180807/p/9456489.html
        config.url = window.localStorage.gatewayDomain + config.url
        
        // 登录时设置 cookies
        var cookies = globalConfig.getCookies()
        if (config.url.indexOf('?') < 0) {
          config.url += '?'
        }
        // 为所有接口加上 access_token
        config.url += ('access_token=' + cookies['access_token'])
        if (!config.data) config.data = {}
        return config;
      }, function (err) {
        // 错误处理
        return Promise.reject(err)
      })
    
      // 添加 axios 响应拦截器
      axios.interceptors.response.use(function (response) {
    
        // 这里是当接口请求服务器成功响应的情况   解构赋值出需要的数据
        const {status, data} = response;
    
        if (status === 200) {
          // 如果不出现错误,直接向回调函数内输出 data  状态200
          if (data.error === 'SUCCESS') {
            // 成功不用提示
            return data
          } else {
            // 若出现错误则弹窗错误提示
            if (data.message) {
              Notification({
                title: '错误',
                message: data.message,
                type: 'error',
                customClass: 'el-error-msg',
                duration: 2000
              })
            }
            return data
          }
        } else {
          return response;
        }
      }, function (error) {
        // 这里是当接口请求失败的情况 (例如服务器没响应、后台代码问题之类的)  (具体的响应判断根据你后台返回状态码结构)
        const {response} = error;
    
        // 这里处理错误的 http code
        if (!response || response.status === 404) {
          if (!response) {  // access_token 失效的情况 弹窗提示
            Notification({
              title: '错误',
              message: 'access_token已失效请重新登录',
              type: 'error',
              customClass: 'el-error-msg',
              duration: 1500,
              onClose() {
                window.location.href = window.localStorage.loginUrl  // 自动跳转返回登录页重新获取access_token
              }
            })
          } else {
            // 这是请求url不对的情况
            console.log('404 error %o' + error);
          }
        }
        // Do something with response error 对响应错误做点什么
        return Promise.reject(error.message);
      });
    };
    
    export default {
      init
    }

    services/prompt.js文件

    const init = function () {
      const _this = this;
      // 建议为了方便使用,这里可以包装window.Alert  具体怎么使用往下看
      window.Alert = function (msg, duration = 3000) {
        // 错误提示
        _this.$notify({
          title: '错误',
          message: msg,
          type: 'error',
          customClass: 'el-error-msg',
          duration
        });
      }
     // 成功提示
      window.Tips = function (msg, duration = 3000) {
        _this.$notify({
          title: '成功',
          message: msg,
          type: 'success',
          duration
        });
      }
     // 警告提示
      window.Warning = function (msg, duration = 3000) {
        _this.$notify({
          title: '警告',
          message: msg,
          type: 'warning',
          duration
        });
      }
    
      // 全局延时器
      window.SetTimeout = function (path, queryObject) {
        setTimeout(_ => {
          _this.$router.push({
            path: path,
            query: queryObject
          });
        }, 500)
      }
    };
    
    export default {
      init
    }

    page/Demo/interface.js文件  (pc端不建议用vuex  具体看需求吧   vuex管理版本 往下看)

    import axios from 'axios';
    
    const ajax = {
      // 获取影像件上传列表
      GET_IMAGE_LIST: 'images?'
    };
    // 提取公共部分
    const API_PATH_PRE_FIX = 'apply/v1/'; 
    
    // 增加接口模块前缀
    let INTERFACE = {};
    for (let key in ajax) {
      INTERFACE[key] = API_PATH_PRE_FIX + ajax[key];
    }
    
    /**
     * 方式1: 多参数情况  获取列表
     * @param data 参数
     * @returns {*}
     */
    function getImageList(data) {
      return axios.get(INTERFACE.GET_IMAGE_LIST, {
        params: data
      }).catch(function (error) {
        window.Alert(error);
      });
    }
    
    /**
     * 方式2: es6模板语法  获取基本信息
     * @param data 参数
     * @returns {*}
     */
    function getContrantInfo(API_PATH_PRE_FIX, agreementId) {
      return axios.get(`${API_PATH_PRE_FIX}/middle/agreement/basic?agreementId=${agreementId}&`).catch(function (error) {
        window.Alert(error);
      });
    }
    export default {
      getImageList,
      getContrantInfo,
    };

    page/Demo/index.vue文件

    <script>
    // 引入上面的接口文件 import INTERFACE from './interface' export default { data() { return { imageList: [], deleteList: [] } }, created() { // 获取列表 (调用封装好的请求) INTERFACE.getImageList().then(data => { if (data && data.data) this.imageList = data.data }) }, methods: { // 确认删除 handleDelete() { INTERFACE.deleteAgreement(this.deleteList).then(data => { // 操作成功提示 (上面定义好的全局提示) window.Tips('删除成功!') }) } } } </script>

    src/main.js文件

    import Vue from 'vue'
    import ElementUI from 'element-ui'
    import App from './App'
    import ajax from '@/services/ajax'
    
    // axios 统一配置
    ajax.init()
    
    // 全局变量
    indow.localStorage.gatewayDomain = 'https://dev-api.cn/'
    window.localStorage.defaultLanguage = 'ZH_CN'

    src/App.vue文件

    <script>
    import prompt from '@/services/prompt'
    export default {
      name: 'app',
      mounted() {
        // 全局错误初始化
        prompt.init.call(this)
      }
    }
    </script>

    以上就是pc端的项目配置化、请求统一管理内容了。有疑问的地方留言看到后会第一时间回复,或可改进的地方欢迎指导, 下面介绍vuex管理版本。

    移动端结合Vuex 统一管理请求 stroe/actions.js文件

    import Vue from 'vue'
    
    // 全局域名
    const apiUrlBase = window.apiUrlBase
    
    const API_URL = {
      GET_APPLICENT: `${apiUrlBase}/app/v1/apply/dictionaries`
    }
    
    const actions = {
       /**
     * 获取投保人数据字典
     */
    actions.getApplicent = ({ state }) => {
      return new Promise((resolve, reject) => {
        Vue.http.get(`${API_URL.GET_APPLICENT}?access_token=${state.accessToken}`).then((ret) => {
            resolve(ret.body)
          }).catch((err) => {
            reject(err)
          })
        })
      }
    }
    
    export default actions

    .vue文件里调用

    this.$store.dispatch(`${storeName}/getApplicent`)
          .then((data) => {
            console.log(data)
          })

    这就可以啦。

    本文为原创 转载请注明出处 。

  • 相关阅读:
    iPhone控件之UIDatePicker
    iPhone控件之UIActionSheet
    iPhone控件之UIActivityView
    iPhone控件之UIPickerView2
    RTP/RTCP协议详解
    ASIHTTPRequest详解[转载]
    iPhone控件之UIProgressView
    iPhone控件之UIPageControl
    iPhone控件之UISegmentedControl
    使用AsyncSocket实现RTSP协议
  • 原文地址:https://www.cnblogs.com/ljx20180807/p/9799545.html
Copyright © 2011-2022 走看看