目录
  • 前言
  • 一、回顾 Vue2 的全局引用方式  
    • 1. 简单项目的全局引用
    • 2. 复杂项目的三步封装
  • 二、Vue3 中的使用 
    • 1. provide/inject 方式
    • 2. getCurrentInstance 组合式API引入
  • 总结

    前言

    边看边学边记录系列,正好到 Vue3 了今天就和大家一起学习并记录一下 Vue3 的Composition API(组合式API) 中是如何全用使用 Axios 的!

    一、回顾 Vue2 的全局引用方式  

    1. 简单项目的全局引用

    如果只是简单几个页面的使用,无需太过复杂的配置就可以直接再 main.js 中进行挂载

    import Vue from "vue";
     
    /* 第一步下载 axios 命令:npm i axios 或者yarn add axios 或者pnpm i axios */
    /* 第二步引入axios */
    import axios from 'axios'
     
     
    // 挂载一个自定义属性$http
    Vue.prototype.$http = axios
    // 全局配置axios请求根路径(axios.默认配置.请求根路径)
    axios.defaults.baseURL = 'http://yufei.shop:3000'
     

    页面使用

    methods:{
        getData(){
            this.$http.get('/barry').then(res=>{
                console.log('res',res)
            )}    }
    }

    2. 复杂项目的三步封装

    ① 新建 util/request.js (配置全局的Axios,请求拦截、响应拦截等)

    关于 VFrame 有疑问的同学可以移步  前端不使用 il8n,如何优雅的实现多语言?

    import axios from "axios";
    import { Notification, MessageBox, Message } from "element-ui";
    import store from "@/store";
    import { getToken } from "@/utils/auth";
    import errorCode from "@/utils/errorCode";
    import Cookies from "js-cookie";
    import VFrame from "../framework/VFrame.js";
    import CONSTANT from '@/CONSTANT.js'
     
    axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8";
    // 创建axios实例
    const service = axios.create({
      // axios中请求配置有baseURL选项,表示请求URL公共部分
      baseURL: process.env.VUE_APP_BASE_API,
      // 超时
      timeout: 120000
    });
    // request拦截器
    service.interceptors.request.use(
      config => {
        // 是否需要设置 token
        const isToken = (config.headers || {}).isToken === false;
        if (getToken() && !isToken) {
          config.headers["Authorization"] = "Bearer " + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        var cultureName = Cookies.get(CONSTANT.UX_LANGUAGE);
        if (cultureName) {
          config.headers[CONSTANT.UX_LANGUAGE] = cultureName; // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        // get请求映射params参数
        if (config.method === "get" && config.params) {
          let url = config.url + "?";
          for (const propName of Object.keys(config.params)) {
            const value = config.params[propName];
            var part = encodeURIComponent(propName) + "=";
            if (value !== null && typeof value !== "undefined") {
              if (typeof value === "object") {
                for (const key of Object.keys(value)) {
                  let params = propName + "[" + key + "]";
                  var subPart = encodeURIComponent(params) + "=";
                  url += subPart + encodeURIComponent(value[key]) + "&";
                }
              } else {
                url += part + encodeURIComponent(value) + "&";
              }
            }
          }
          url = url.slice(0, -1);
          config.params = {};
          config.url = url;
        }
        return config;
      },
      error => {
        console.log(error);
        Promise.reject(error);
      }
    );
     
    // 响应拦截器
    service.interceptors.response.use(
      res => {
        // 未设置状态码则默认成功状态
        const code = res.data.code || 200;
        // 获取错误信息
        const msg = errorCode[code] || res.data.msg || errorCode["default"];
        if (code === 401) {
          MessageBox.alert(
            VFrame.l("SessionExpired"),
            VFrame.l("SystemInfo"),
            {
              confirmButtonText: VFrame.l("Relogin"),
              type: "warning"
            }
          ).then(() => {
            store.dispatch("LogOut").then(() => {
              location.href = "https://www.freexyz.cn/index";
            });
          });
        } else if (code === 500) {
          Message({
            message: msg,
            type: "error"
          });
          if (res.data.data) {
            console.error(res.data.data)
          }
          return Promise.reject(new Error(msg));
        } else if (code !== 200) {
          Notification.error({
            title: msg
          });
          return Promise.reject("error");
        } else {
          if (res.data.uxApi) {
            if (res.data.success) {
              return res.data.result;
            } else {
              Notification.error({ title: res.data.error });
              console.error(res);
              return Promise.reject(res.data.error);
            }
          } else {
            return res.data;
          }
        }
      },
      error => {
        console.log("err" + error);
        let { message } = error;
        if (message == "Network Error") {
          message = VFrame.l("TheBackEndPortConnectionIsAbnormal");
        } else if (message.includes("timeout")) {
          message = VFrame.l("TheSystemInterfaceRequestTimedOut");
        } else if (message.includes("Request failed with status code")) {
          message =
            VFrame.l("SystemInterface") +
            message.substr(message.length - 3) +
            VFrame.l("Abnormal");
        }
        Message({
          message: VFrame.l(message),
          type: "error",
          duration: 5 * 1000
        });
        return Promise.reject(error);
      }
    );
     
    export default service;

    ② 新建 api/login.js (配置页面所需使用的 api)

    import axios from "axios";
    import { Notification, MessageBox, Message } from "element-ui";
    import store from "@/store";
    import { getToken } from "@/utils/auth";
    import errorCode from "@/utils/errorCode";
    import Cookies from "js-cookie";
    import VFrame from "../framework/VFrame.js";
    import CONSTANT from '@/CONSTANT.js'
     
    axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8";
    // 创建axios实例
    const service = axios.create({
      // axios中请求配置有baseURL选项,表示请求URL公共部分
      baseURL: process.env.VUE_APP_BASE_API,
      // 超时
      timeout: 120000
    });
    // request拦截器
    service.interceptors.request.use(
      config => {
        // 是否需要设置 token
        const isToken = (config.headers || {}).isToken === false;
        if (getToken() && !isToken) {
          config.headers["Authorization"] = "Bearer " + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        var cultureName = Cookies.get(CONSTANT.UX_LANGUAGE);
        if (cultureName) {
          config.headers[CONSTANT.UX_LANGUAGE] = cultureName; // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        // get请求映射params参数
        if (config.method === "get" && config.params) {
          let url = config.url + "?";
          for (const propName of Object.keys(config.params)) {
            const value = config.params[propName];
            var part = encodeURIComponent(propName) + "=";
            if (value !== null && typeof value !== "undefined") {
              if (typeof value === "object") {
                for (const key of Object.keys(value)) {
                  let params = propName + "[" + key + "]";
                  var subPart = encodeURIComponent(params) + "=";
                  url += subPart + encodeURIComponent(value[key]) + "&";
                }
              } else {
                url += part + encodeURIComponent(value) + "&";
              }
            }
          }
          url = url.slice(0, -1);
          config.params = {};
          config.url = url;
        }
        return config;
      },
      error => {
        console.log(error);
        Promise.reject(error);
      }
    );
     
    // 响应拦截器
    service.interceptors.response.use(
      res => {
        // 未设置状态码则默认成功状态
        const code = res.data.code || 200;
        // 获取错误信息
        const msg = errorCode[code] || res.data.msg || errorCode["default"];
        if (code === 401) {
          MessageBox.alert(
            VFrame.l("SessionExpired"),
            VFrame.l("SystemInfo"),
            {
              confirmButtonText: VFrame.l("Relogin"),
              type: "warning"
            }
          ).then(() => {
            store.dispatch("LogOut").then(() => {
              location.href = "https://www.freexyz.cn/index";
            });
          });
        } else if (code === 500) {
          Message({
            message: msg,
            type: "error"
          });
          if (res.data.data) {
            console.error(res.data.data)
          }
          return Promise.reject(new Error(msg));
        } else if (code !== 200) {
          Notification.error({
            title: msg
          });
          return Promise.reject("error");
        } else {
          if (res.data.uxApi) {
            if (res.data.success) {
              return res.data.result;
            } else {
              Notification.error({ title: res.data.error });
              console.error(res);
              return Promise.reject(res.data.error);
            }
          } else {
            return res.data;
          }
        }
      },
      error => {
        console.log("err" + error);
        let { message } = error;
        if (message == "Network Error") {
          message = VFrame.l("TheBackEndPortConnectionIsAbnormal");
        } else if (message.includes("timeout")) {
          message = VFrame.l("TheSystemInterfaceRequestTimedOut");
        } else if (message.includes("Request failed with status code")) {
          message =
            VFrame.l("SystemInterface") +
            message.substr(message.length - 3) +
            VFrame.l("Abnormal");
        }
        Message({
          message: VFrame.l(message),
          type: "error",
          duration: 5 * 1000
        });
        return Promise.reject(error);
      }
    );
     
    export default service;

    ③ 页面使用引入

    import { login } from "@/api/login.js"
    接下来不用多说,相信大家已经会使用了

    二、Vue3 中的使用 

    上面回顾完 Vue2 中使用 axios 我们来一起看看 Vue3 中axios的使用( 简单Demo,前台使用Vue3,后台使用 node.js ),仅供学习!

    1. provide/inject 方式

    ① main.js 中 使用 provide 传入

    import {
        createApp
    } from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    import "lib-flexible/flexible.js"
     
    import axios from "@/util/request.js"
     
    const app = createApp(App);
     
     
     
    app.provide('$axios', axios)
    app.use(store).use(router).mount('#app');

    ② 需要用到的页面使用 inject 接受

    import { ref, reactive, inject, onMounted} from "vue";
     
    export default {
      setup() {
     
        const $axios = inject("$axios");
     
        const getData = async () => {
          data = await $axios({ url: "/one/data" });
          console.log("data", data);
        };
     
        onMounted(() => {
            
          getData()
     
        })
     
        return { getData }
     
      }
     
    }

    这个就是借助 provide 做一个派发,和 Vue2 中的差距使用方法差距不大 

    2. getCurrentInstance 组合式API引入

     ① main.js 中挂载

    import {
        createApp
    } from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    import "lib-flexible/flexible.js"
     
    import axios from "@/util/request.js"
     
    const app = createApp(App);
     
    /* 挂载全局对象 */
    app.config.globalProperties.$axios = axios;
     
    app.use(store).use(router).mount('#app');

    /* 挂载全局对象 */
    app.config.globalProperties.$axios = axios;

    重点就是上面这句

    ② 需要用的页面使用 Composition Api — getCurrentInstance 拿到

    <script>
    import { reactive, onMounted, getCurrentInstance } from "vue";
    export default {
      setup() {
        let data = reactive([]);
        /**
         * 1. 通过getCurrentInstance方法获取当前实例
         * 再根据当前实例找到全局实例对象appContext,进而拿到全局实例的config.globalProperties。
         */
        const currentInstance = getCurrentInstance();
        const { $axios } = currentInstance.appContext.config.globalProperties;
     
        /**
         * 2. 通过getCurrentInstance方法获取上下文,这里的proxy就相当于this。
         */
     
        const { proxy } = currentInstance;
     
     
        const getData = async () => {
          data = await $axios({ url: "/one/data" });
          console.log("data", data);
        };
     
        const getData2 = async () => {
          data = await proxy.$axios({ url: "/one/data" });
          console.log("data2", data);
        };
     
        onMounted(() => {
     
          getData()
     
        });
        return { getData };
      },
    };
    </script>

    下图可以看到我们确实调用了 2次 API 

    Vue3全局配置axios的两种方式总结

    其实通过 Composition API 中的 getCurrentInstance 方法也是有两种方式的

     1. 通过 getCurrentInstance 方法获取当前实例,再根据当前实例找到全局实例对象appContext,进而拿到全局实例的config.globalProperties。        

    const currentInstance = getCurrentInstance();
    const { $axios } = currentInstance.appContext.config.globalProperties;

     2. 通过getCurrentInstance方法获取上下文,这里的proxy就相当于this。

    const currentInstance = getCurrentInstance();
     
    const { proxy } = currentInstance;
     
    const getData2 = async () => {
          data = await proxy.$axios({ url: "/one/data" });
          console.log("data2", data);
    };

    总结

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。