Vue + Ts 封装axios 及 全局方法挂载

前言

typescript 的大环境下,我们前期通过 vue-cli 脚手架创建了新项目,这时需要用到 axios 对接后端接口。那么这种情况下,我们从网上搜索到相关的文档及博客去做进一步封装。

我也从中学到了许多,也将其中不错的部分提炼并用在自己的项目中,后续还会继续改进,可以供大家参考。

其中,注意的事项点写在代码的备注中。

Axios的封装

整理思路
  • index.ts

我们需要在src的根目录下创建一个axios文件夹,其中创建一个index.ts文件,这个文件主要用来封装axios的配置(实例化请求配置、请求拦截器、相应拦截器)及相应的方法(登录跳转、消息提示、错误处理等)

  • base.ts

这个文件主要用于项目扩展的情况下 不同模块需要调用不同接口(请求的base地址 baseURL )而前期做的准备,便于后期的维护

  • request.ts

主要用于封装基于axios配置的get/post/put/delete等使用方法。

  • api.ts

在后面的 main.ts 中引入该模块,包括所有接口数据信息写入该文件中。

目录结构
-- src
	-- axios
		index.ts
		base.ts
		request.ts
		api.ts

代码如下:

index.ts

提示工具用到了element-ui,封装如下。考虑到单一职责,index这块只封装axios就足矣。

// index.ts
import axios from "axios";
import router from "@/router";
import store from "@/store";
import { Message } from "element-ui";

const message = (msg: string,type?: any) => {    
    Message({
      message: msg,
      type: type || 'warning',
      duration:1500,
    });
}

/** 
 * 跳转登录页
 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
 */
const toLogin = () => {
    router.replace({
      name: 'LoginPage',
    });
}

/** 
 * 请求失败后的错误统一处理 
 * @param {Number} status 请求失败的状态码
 */
const errorHandle = (status: number, other: string) => {
  // 状态码判断
  switch (status) {
    // -1: 未登录状态,跳转登录页
    case -1:
      toLogin();
      break;
    // 403 token过期
    // 清除token并跳转登录页
    case 403:
      message('登录过期,请重新登录');
      localStorage.removeItem('token');
      store.commit('token', null);
      setTimeout(() => {
        toLogin();
      }, 1000);
      break;
    // 404请求不存在
    case 404:
      message('请求的资源不存在');
      break;
    default:
      message(other);
  }
}



/* 实例化请求配置 */
const instance = axios.create({
  headers: {
    //php 的 post 传输请求头一定要这个 不然报错 接收不到值
    "Content-Type": "application/x-www-form-urlencoded", 
  },
  // 请求时长
  timeout: 1000 * 30,
  // 请求的base地址 TODO:这块以后根据不同的模块调不同的api
    // baseURL:
    //   process.env.NODE_ENV === "development"
    //     ? "测试"
    //     : "正式",
  withCredentials: true,
})

/** 
 * 请求拦截器 
 * 每次请求前,如果存在token则在请求头中携带token 
 */ 
instance.interceptors.request.use(
  config => {        
      // 登录流程控制中,根据本地是否存在token判断用户的登录情况        
      // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token        
      // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码        
      // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。        
    const token = store.state.token;
    localStorage.setItem('token', token);
      token && (config.headers.Authorization = token)
      return config;
    },    
    // error => Promise.error(error)
)

  
  // 响应拦截器
instance.interceptors.response.use(
  // 请求成功
  res => res.status === 200 ? Promise.resolve(res.data) : Promise.reject(res),
  // 请求失败
  error => {
        const { response } = error;
        if (response) {
            // 请求已发出,但是不在2xx的范围 
            errorHandle(response.status, response.data.message);
            return Promise.reject(response);
        } else {
            // 处理断网的情况
            // eg:请求超时或断网时,更新state的network状态
            // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
            // 后续增加断网情况下做的一些操作
            store.commit('networkState', false);
            ...
        }
  }
)    


// 只需要考虑单一职责,这块只封装axios
export default instance
base.ts

区分每个模块的 baseUrl 方便后期维护管理

// base.ts
export default class Base {
  /* 公共模块 */
  static common = process.env.NODE_ENV === "development" 
  ? "https://testCommon.com(测试线地址)" 
  : "https://produceCommon.com(生产线地址)"
  /* 活动模块 */
  static active = process.env.NODE_ENV === "development" 
  ? "https://testActive.com(活动测试线地址)" 
  : "https://produceActive.com(活动生产线地址)"

}
request.ts

封装axios的get、post方法,其余关于接口调用的方法也可写入该文件中,便于管理。

// request.ts
import axios from "./index";
import qs from "qs";

export default class Request{
  /**
   * get方法
   * @param {string} url 路径
   * @param {object} params 参数
   */
  static get = (url: string, params?: object) => {
    return new Promise((resolve, reject) => {
      axios.get(url, { params: params }).then(res => {
        resolve(res);
      }).catch(err => {
        reject(err);
      })
    })
  }
    
  static post = (url: string, params?: object) => {
    return new Promise((resolve, reject) => {
      axios.post(url, qs.stringify(params)).then(res => {
        resolve(res);
      }).catch(err => {
        reject(err);
      })
    })
  }  
  
}

api.ts

其中使用 install 的目的在于 ts 在main.ts中 不能通过Vue.prototype.$Api这个方式直接调用,在全局方法中会说到使用 插件的方式去挂载。

// api.ts
import base from "./base";
import request from "./request";

class Api {
  /* 公共模块 */
  public static common = {
    genre: (params = {}) => request.get(`${base.common}frontend/genre`, params),
  }

  /* 活动模块 */
  public static active = {
    
  }
}

const protoApi = {
  install: (Vue: any) => {
    Vue.prototype.$Api = Api
  }
}

export default protoApi

全局挂载

在上述的 api.ts 中我们看到需要用到插件的方式去全局挂载,整个流程步骤我会在如下的代码中粘贴出来。

一、在 api.ts 中导出

// api.ts
import base from "./base";
import request from "./request";

class Api {
  /* 公共模块 */
  public static common = {
    genre: (params = {}) => request.get(`${base.common}frontend/genre`, params),
  }
  /* 活动模块 */
  public static active = {
    
  }
}
const protoApi = {
  install: (Vue: any) => {
    Vue.prototype.$Api = Api
  }
}

export default protoApi

二、在 main.ts 中导入

// main.ts
import api from "./axios/api";

// 由于api该模块已经注册成组件了,所以main中直接使用该组件便可
Vue.use(api)

三、在src的根目录下创建一个ts为 vue-prototype.d.ts,该命名方式为 *.d.ts,无需一样。

-- src
	-- vue-prototype.d.ts
// vue-prototype.d.ts
import Vue from "vue";
import api from "./axios/api";

declare module "vue/types/vue" {
    interface Vue {
        $Api:api;
    }
}

四、最后在我们的模版中调用该方法即可。

注:如下看到 $Api 方法在 eslint 下报错 Property $Api does not exist on type 等字眼,只需重启下vscode编译器即可。

// LoginPage.vue
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  name: 'LoginPage',
})
export default class LoginPage extends Vue {
	mounted(): void {
		this.$Api.common.genre().then((res: object) => {
	      console.log("公共方法",res)
	    })
	    // 活动
	    this.$Api.active.xxx().then()
	}
}
</script>

总结

在封装的过程中 我们总会遇到一些坑,不过好在看了挺多大部分网上不错的解决方案,结合自己的思路也是可以做到的。

  • 12
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue3中使用TypeScript和Axios,你可以按照以下步骤完成全局封装: 1. 安装 Axios 和 @types/axios: ```bash npm install axios @types/axios --save ``` 2. 创建 `api.ts` 文件来封装 Axios 请求: ```typescript import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; interface HttpConfig extends AxiosRequestConfig { // 自定义配置 } class Http { private axiosInstance: AxiosInstance; constructor() { this.axiosInstance = axios.create({ // 基础请求路径 baseURL: process.env.BASE_API, // 请求超时时间 timeout: 5000, }); // 请求拦截器 this.axiosInstance.interceptors.request.use( (config: HttpConfig) => { // 在请求前做些什么 return config; }, (error: any) => { // 处理请求错误 Promise.reject(error); } ); // 响应拦截器 this.axiosInstance.interceptors.response.use( (response: AxiosResponse) => { // 对响应数据做些什么 return response.data; }, (error: any) => { // 处理响应错误 Promise.reject(error); } ); } // 封装请求方法 public request<T>(config: HttpConfig): Promise<T> { return this.axiosInstance.request<T>(config); } // 封装 get 请求 public get<T>(url: string, config?: HttpConfig): Promise<T> { return this.axiosInstance.get<T>(url, config); } // 封装 post 请求 public post<T>(url: string, data?: any, config?: HttpConfig): Promise<T> { return this.axiosInstance.post<T>(url, data, config); } // 封装 put 请求 public put<T>(url: string, data?: any, config?: HttpConfig): Promise<T> { return this.axiosInstance.put<T>(url, data, config); } // 封装 delete 请求 public delete<T>(url: string, config?: HttpConfig): Promise<T> { return this.axiosInstance.delete<T>(url, config); } } export default new Http(); ``` 3. 在 `main.ts` 中引入 `api.ts` 并挂载Vue 实例上: ```typescript import { createApp } from 'vue'; import App from './App.vue'; import api from './api'; const app = createApp(App); app.config.globalProperties.$api = api; app.mount('#app'); ``` 现在,你就可以在任何组件中使用 `$api` 来调用 Axios 请求了: ```typescript <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ mounted() { this.$api.get('/api/user').then((res) => { console.log(res); }); }, }); </script> ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值