Vue工程化封装实践系列(一)[axios封装+bus事件总线]

4,118 阅读3分钟

本系列旨在将自己工程实践中使用的Vue工程化相关方法做一个总结,分享出来欢迎各位指正!本系列大纲暂定如下,会在最近不断更新,并在整理完全部之后将自己的工程demo发布在github:github.com/Joseph244

  1. axios封装+ vue-bus全局事件通信
  2. vue防止表单重复提交,请求队列取消方法
  3. 组件自动注册+vuex模块自动载入
  4. vuex封装+vuex数据的本地化存储
  5. 路由分模块自动载入
  6. 权限指令封装
  7. 更简洁的代码:render函数
  8. mixin混入
  9. 全局过滤器
  10. directive自定义指令
  11. echarts resize窗口自适应
  12. vue动画高级
  13. less全局变量抽离+自定义多环境打包

axios封装

与后端约定所有接口返回的数据格式如下:

{
    code: 200,  // 200 成功,!200 服务端接口异常
    data: '请求业务数据',
    msg: 'err message'
}

** 封装要求 ** 1.请求参数统一使用{data: params},并在拦截器根据请求方式转换; 2.请求状态码和Not Found消息统一处理; 3.根据自定义接口code状态码,减少页面处理返回值之后还要判断response.code == 200等逻辑处理: code == 200,返回response.data; post、put请求自动根据接口的msg返回提示信息(xxx添加成功) code !== 200 自动提示接口msg错误信息;

** 代码来了 **

// http.js
import Axios from 'axios'; // 此处引入axios官方文件
import { Notification } from 'element-ui';

const axios = Axios.create({
    baseURL: 'xxxxx',   // 服务端接口baseUrl
    timeout: 30000
});


// 添加请求拦截器
axios.interceptors.request.use(
    function(config) {
        if (config.method.toLocaleLowerCase() === 'post' || config.method.toLocaleLowerCase() === 'put') {
            // 参数统一处理,请求都使用data传参
            config.data = config.data.data;
        } else if (config.method.toLocaleLowerCase() === 'get' || config.method.toLocaleLowerCase() === 'delete') {
            // 参数统一处理
            config.params = config.data;
        } else {
            alert('不允许的请求方法:' + config.method);
        }
        return config;
    },
    function(error) {
        // 对请求错误做些什么
        return Promise.reject(error);
    }
);

// 添加响应拦截器
axios.interceptors.response.use(
    function(response) {
        // 接口数据处理
        if (response.data === 'Not Found') {
            // 由于不存在的接口有时候会返回Not Found,所以做了特殊处理
            Notification({
                title: response.config.url,
                message: '资源不存在',
                type: 'error'
            });
        } else if (response.status == 200 || response.status == 304) {
            // 自定义约定接口返回{code: xxx, data: xxx, msg:'err message'}
            // code:200 数据正常; !200 数据获取异常
            if (response.data.code == 200) {
                if (response.config.method.toLocaleLowerCase() === 'post' || response.config.method.toLocaleLowerCase() === 'put') {
                    Notification({
                        title: '成功',
                        message: response.data.msg,
                        type: 'success'
                    });
                }
                return response.data.data;
            } else {
                Notification({
                    title: response.config.url,
                    message: response.data.msg,
                    type: 'error'
                });
            }
        } else {
            Notification({
                title: response.config.url,
                message: '服务器繁忙,请稍后重试!',
                type: 'error'
            });
        }
    },
    function(error) {
        Notification({
            title: '接口异常',
            message: error.message,
            type: 'error'
        });
        return Promise.reject(error);
    }
);
export default axios;

使用案例:

import http from './http'

export default {
  queryList(data) {
    return http.get('/books/index', { data: data })
  },
  postTest(data) {
    return http.post('/books/create', { data: data })
  },
  postTest400(data) {
    return http.post('/books/create400', { data: data })
  },
  notFoundApi(data) {
    return http.post('/xxx/create123', { data: data })
  }
}

xxx.vue

<template>
  <div id="app">
    <button @click="queryList">查询</button>
    <button @click="postBtn">POST</button>
    <button @click="postBtn400">POST400</button>
    <button @click="notFoundBtn">notFoundBtn</button>
    <div>{{ tableData }}</div>
  </div>
</template>

<script>
import api from './api.js'
export default {
  name: 'App',
  data() {
    return {
      tableData: []
    }
  },
  methods: {
    queryList() {
      api.queryList({ test: 1233 }).then(res => {
        this.tableData = res
      })
    },
    postBtn() {
      api.postTest({ posttt: 2222 })
    },
    postBtn400() {
      api.postTest400({ posttt: 400 })
    },
    notFoundBtn() {
      api.notFoundApi({ aya: 666 }).then(res => {
        console.log(res)
      })
    }
  }
}
</script>

vue防止表单重复提交,请求队列取消方法

请查看访问本人另一篇掘金博客:表单按钮重复提交,axios重复请求的处理方案

vue-bus全局事件通信

** 注意: ** 1.bus.on 应该在created钩子函数中使用,如果在mounted中使用可能会出现接收不到触发消息;
2.使用结束页面退出时,要在beforeDestory钩子函数中使用bus.off解除,因为组件销毁就没必要留着句柄占用存储了; 3. 监听事件this.$bus.on('add', this.event_xxx);( this.event_xxx可以是一个参数也可以是一个在methods中定义过的方法)。 ** 封装代码 ** 封装一个vue-bus的js文件给main.js调用

// vue-bus.js
const install = function (Vue) {
    const Bus = new Vue({
        methods: {
            emit (event, ...args) {
                this.$emit(event, ...args);
            },
            on (event, callback) {
                this.$on(event, callback);
            },
            off (event, callback) {
                this.$off(event, callback);
            }
        }
    });
    Vue.prototype.$bus = Bus;
};

export default install;
main.js
...   ...
import VueBus from './vue-bus.js';

Vue.use(VueBus);

这样我们就可以使用如下方法使用

//  this.$bus.emit('add', params);   // 触发事件(parms为触发传递的参数)

created () {
    this.$bus.on('add', this.handleAddRandom);    // 监听事件参数(this.handleAddRandom可以是一个参数也可以是一个方法)
},
beforeDestroy () {
    this.$bus.off('add', this.handleAddRandom);     // 销毁事件
}