教你vue下axios二次封装,支持防抖,错误处理,成功失败提示(新手看看,大佬留情)

3,750 阅读7分钟

项目痛点:

重复写成功提示,错误提示

每次都需要判断后端返回的数据是真还是假

表单提交之后阻止用户重复点击

即时表单提交了,出现加装阻止提示了,但是在程序反应过来之前,用户还是能多次提交

最后附带微信小程序ajax封装个人案例

1、ajax参数列表

url //接口地址

isAntiShake //是否防抖(默认不防抖)
shakeTime //默认防抖时间半秒
loading //是否出现全局加载提示,支持传入字符串,传入字符串则提示字符串加载信息
data //接口传入数据
filterNull //是否对data数据过滤空数据 默认true
headers //默认 {"Content-Type": "application/json;charset=UTF-8"}
is_suc //成功提示默认 操作成功,传入字符串则提示字符串

is_err //失败提示 默认 网络异常,传入字符串则提示字符串

method //默认get

1.1、功能说明:

上面参数上很明显的我就不说了

主要实现功能:

全局错误或者成功提示

防抖处理(先发送请求,后进行防抖,网上很多教程都是先防抖后发送请求)

全局loading加载提示

封装自己的业务ajax回调数据

axios的get和post格式的统一处理,原axios的get和post代码居然不一样

说明:

vue环境下,配合elmentUI,vue-axios

2、代码解析:

导入代码部分,这个没什么可说的

import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";

import { Notification, Loading } from "element-ui";

// axios全局导入设置
Vue.use(VueAxios, axios);

2.1、msg提示信息部分

//自定义函数信息
let custom = {
  //成功信息提示
  sucIfno(info) {
    Notification({
      type: "success",
      message: info
    });
  },
  //错误信息提示
  errIfno(info) {
    Notification({
      type: "error",
      message: info
    });
  }
};

2.2、过滤空数据(这里注意一下,我会过滤字符串当初出现的NaN|undefined|null字符,这里建议自己改写,或者不要它,有时候画蛇添足)

//过滤空数据包含NaN,undefined,null
const filterNull = json => {
  let newJson = {};
  let reg = RegExp(/NaN|undefined|null/);
  for (let li in json) {
    if (json[li] && !reg.test(json[li])) {
      newJson[li] = json[li];
    }
  }
  return newJson;
};

2.2、核心部分,ajax封装部分

这里主要看我注释,我注释重新改写了,更加详细。

这里用了promise封装

const ajax = o => {
  o.loading = o.loading || false; //是否出现全局加载提示,支持传入字符串
  o.data = o.data || {}; //传入的data参数
  o.filterNull = o.filterNull !== false; //默认过滤空数据,不想要这个功能的就直接改成true
  o.headers = o.headers || { //默认的herders参数部分
    "Content-Type": "application/json;charset=UTF-8"
  };

  //成功提示信息,传入true则提示默认信息,传入字符串则出现字符串信息
  o.is_suc = o.is_suc || false;
  o.is_suc = o.is_suc === true ? "操作成功" : o.is_suc;
  //错误提示信息,默认不出现,传入true则出现后端接口提示信息,传入字符串则提示字符串信息
  o.is_err = o.is_err || false;
  o.is_err = o.is_err === true ? "网络异常" : o.is_err;

  //空数据过滤
  o.data = o.filterNull === true ? filterNull(o.data) : o.data;

  const method = o.method;
  let loadingInstance = ""; //提示信息框声明
//loading加载框部分
  if (o.loading) {
    loadingInstance = Loading.service({
      lock: true,
      text: o.loading !== true ? o.loading : "努力加载中……",
      spinner: "el-icon-loading",
      background: "rgba(0, 0, 0, 0.7)"
    });
  }
  return new Promise((suc, err) => {
    axios({
      url: o.url,
      [method === "post" ? "data" : "params"]: o.data,
      headers: o.headers,
      method: method || "get"
    })
      .then(t => {
        if (o.loading) { //loading关闭
          loadingInstance.close();
        }
        let req = t.data;
        //自己的业务代码判断处理,这样就可以避免说自己得到参数之后在判断一次参数是正确还是错误
        //这里是封装的核心所在,因为,能省很多代码量,不过需要后端的接口返回数据规范化,不然886
        if (req && req.code === 0) {
          //正确提示信息
          o.is_suc !== false && custom.sucIfno(o.is_suc);
          suc(req);
        } else {// 业务代码判断为后端错误信息则进入promise的错误环节
          //错误信息提示
          if (o.is_err !== false) {//这里注意,错误信息比较多变,大家首先错误信息不为fasle才可以提示
            o.is_err !== "网络异常" //这里判断是否自定义了错误信息,然后根据三元表达式处理就行了
              ? custom.errIfno(o.is_err)
                //这里也是业务代码部分,没有自定义的情况下优先提示后端错误信息
              : custom.errIfno(req.msg ? req.msg : "网络异常"); 
          }
          err(req);
        }
      })
      .catch(e => {//catch部分没啥可讲了吧
        if (o.loading) {
          loadingInstance.close();
        }
        //错误信息提示
        o.is_err !== false ? custom.errIfno("网络异常") : false;
        err(e);
      });
  });
};

2.3、防抖处理

我这里的防抖就简单多了,没有使用闭包,纯粹的变量的使用。

这里其实大家要理解,每一个模块的变量都在自己的作用域中,并且变量会持续存在,这其实就和闭包的原理很像。(大家一定要懂原理,而不是懂代码,利用闭包的设计模式思维)

如果利用闭包的方式来写,我自己很难写出来,而且没必要。

一样看注释

/*防抖处理缺陷:
 当两个函数同时需要防抖的时候另一个函数也会受到防抖的影响,所以请避免同时需要防抖。如需要,额外处理第二个防抖函数。
 * */
let timeOut = null;
axios.ajax = opt => {
  //是否防抖
  let isAntiShake = opt.isAntiShake || false;
  let shakeTime = opt.shakeTime || 500; //默认防抖时间半秒
  if (!isAntiShake) {
    //不进行防抖处理,直接把参数请求给ajax函数
    return new Promise((suc, err) => {
      ajax(opt)
        .then(e => {
          suc(e);
        })
        .catch(e => {
          err(e);
        });
    });
  } else {
    //进行防抖处理
    return new Promise((suc, err) => {
        //清理原先的定时器
      timeOut && clearTimeout(timeOut);
      let callNow = !timeOut; //判断是否运行过了
      if (callNow) {//先执行ajax函数
        ajax(opt)
          .then(e => {
            suc(e);
          })
          .catch(e => {
            err(e);
          });
      }
    //释放内存和还原
      timeOut = setTimeout(
        () => {
          timeOut = null;
        }, 
        shakeTime
      );
    });
  }
};

4、完整的代码结构

有需要的自己拿去改写

main.js导入

//ajax导入
import ajax from "./common/ajax/axios";

注册部分

new Vue({
  ajax,
  router,
  store,
  render: h => h(App)
}).$mount("#app");

完整的main.js

import Vue from "vue";
import App from "./App.vue";
import router from "./common/router/router";
import store from "./common/vuex/store";

//ajax导入,看这里就行了
import ajax from "./common/ajax/axios";
//全局样式载入
import "./assets/css/restCss.css"; //样式重置
//组件注册全部依赖于该文件
import gcomponents from "./components/g_register"; //全局组件
Vue.use(gcomponents);
//全局api接口
import api from "@/common/api/api";
Vue.prototype.$ybs = api;

Vue.config.productionTip = false;

new Vue({
  ajax,
  router,
  store,
  render: h => h(App)
}).$mount("#app");

完整的ajax部分

import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";

import { Notification, Loading } from "element-ui";

// axios全局导入设置
Vue.use(VueAxios, axios);

//自定义函数信息
let custom = {
  //成功信息提示
  sucIfno(info) {
    Notification({
      type: "success",
      message: info
    });
  },
  //错误信息提示
  errIfno(info) {
    Notification({
      type: "error",
      message: info
    });
  }
};
//过滤空数据包含NaN,undefined,null
const filterNull = json => {
  let newJson = {};
  let reg = RegExp(/NaN|undefined|null/);
  for (let li in json) {
    if (json[li] && !reg.test(json[li])) {
      newJson[li] = json[li];
    }
  }
  return newJson;
};
const ajax = o => {
  o.loading = o.loading || false; //是否出现全局加载提示,支持传入字符串
  o.data = o.data || {};
  o.filterNull = o.filterNull !== false;
  o.headers = o.headers || {
    "Content-Type": "application/json;charset=UTF-8"
  };

  //成功提示信息,传入true则提示默认信息,传入字符串则出现字符串信息
  o.is_suc = o.is_suc || false;
  o.is_suc = o.is_suc === true ? "操作成功" : o.is_suc;
  //错误提示信息,默认不出现,传入true则出现后端接口提示信息,传入字符串则提示字符串信息
  o.is_err = o.is_err || false;
  o.is_err = o.is_err === true ? "网络异常" : o.is_err;

  //空数据过滤
  o.data = o.filterNull === true ? filterNull(o.data) : o.data;

  const method = o.method;
  let loadingInstance = "";
  if (o.loading) {
    loadingInstance = Loading.service({
      lock: true,
      text: o.loading !== true ? o.loading : "努力加载中……",
      spinner: "el-icon-loading",
      background: "rgba(0, 0, 0, 0.7)"
    });
  }
  return new Promise((suc, err) => {
    axios({
      url: o.url,
      [method === "post" ? "data" : "params"]: o.data, //axios最坑的地方,post和get居然参数不一样
      headers: o.headers,
      method: method || "get" //默认get处理
    })
      .then(t => {
        if (o.loading) {
          loadingInstance.close();
        }
        let req = t.data;
        if (req /*&& req.code === 0*/) {
          //正确提示信息
          o.is_suc !== false && custom.sucIfno(o.is_suc);
          suc(req);
        } else {
          //错误信息提示
          if (o.is_err !== false) {
            o.is_err !== "网络异常"
              ? custom.errIfno(o.is_err)
              : custom.errIfno(req.msg ? req.msg : "网络异常");
          }
          err(req);
        }
      })
      .catch(e => {
        if (o.loading) {
          loadingInstance.close();
        }
        //错误信息提示
        o.is_err !== false ? custom.errIfno("网络异常") : false;
        err(e);
      });
  });
};
/*防抖处理缺陷:
 当两个函数同时需要防抖的时候另一个函数也会受到防抖的影响,所以请避免同时需要防抖。如需要,额外处理第二个防抖函数。
 * */
let timeOut = null;
axios.ajax = opt => {
  //是否防抖
  let isAntiShake = opt.isAntiShake || false;
  let shakeTime = opt.shakeTime || 500; //默认防抖时间半秒
  if (!isAntiShake) {
    //不进行防抖处理
    return new Promise((suc, err) => {
      ajax(opt)
        .then(e => {
          suc(e);
        })
        .catch(e => {
          err(e);
        });
    });
  } else {
    //进行防抖处理
    return new Promise((suc, err) => {
      timeOut && clearTimeout(timeOut);
      let callNow = !timeOut;
      if (callNow) {
        ajax(opt)
          .then(e => {
            suc(e);
          })
          .catch(e => {
            err(e);
          });
      }
      timeOut = setTimeout(
        () => {
          timeOut = null;
        }, //见注解
        shakeTime
      );
    });
  }
};

export default axios;


最后:

代码其实很烂,而且很渣,主要是其中的业务设计和原理

外链:微信小程序的ajax封装(自己在csdn的博客)

https://blog.csdn.net/qq_32858649/article/details/92830543