likes
comments
collection
share

vite+vue3项目从0到1搭建(3)---请求封装

作者站长头像
站长
· 阅读数 15
  • 安装 axios
 pnpm i axios
  • 在根目录下新建 service 文件夹,进行 axios 封装

目录结构如下

vite+vue3项目从0到1搭建(3)---请求封装

  • modules: 区分每个模块下的请求,如登录退出的房 auth.js 中,首页相关请求放 home.js
  • index: 用于同一暴露各个模块的请求
  • request: 二次封装的请求类

实现一个 Request 类,对 axios 的二次封装

  • 初始化请求相关的信息
 // request.js
 import axios from "axios";
 ​
 class Request {
   constructor(baseURL, timeout) {
     this.instance = axios.create({
       baseURL,
       timeout,
       // 添加默认的Content-Type
       headers: { "Content-Type": "application/x-www-form-urlencoded" }
     });
 ​
     this.showLoading = false; // 用于控制loading
     this.loadingInstance = null; // loading实例
     this.interceptorsSetup(); // 建立请求拦截和响应拦截
   }
 }
 ​
 const { VITE_BASE_URL } = import.meta.env;
 const request = new Request(VITE_BASE_URL, 2000);
 ​
 export default request;
  • 实现请求和响应拦截
 import router from "@/router";
 import useLoading from "@/hooks/useLoading";
 class Request {
   ...
    
   interceptorsSetup() {
     this.instance.interceptors.request.use(
       (config) => {
         // 判断请求时有没有传入loading
         this.showLoading = config.showLoading ?? this.showLoading;
         // 有传入loading就显示
         if (this.showLoading) {
           const { loadingInstance } = useLoading();
           this.loadingInstance = loadingInstance;
         }
         // 有token则带上到请求头中
         const token = localStorage.getItem("token") || "";
         if (token) {
           config.headers && (config.headers["token"] = token);
         }
         return config;
       },
       (err) => {
         console.error("网络请求出错", err);
         this.loadingInstance?.close();
         return err;
       }
     );
 ​
     this.instance.interceptors.response.use(
       (response) => {
         // 请求完成,关闭loading
         this.loadingInstance?.close();
         const { code } = response.data;
 ​
         // 判断token是否过期,过期则跳转到登录页面并清除token
         if (code === 401) {
           localStorage.removeItem("token");
           router.replace("/login");
           return Promise.reject(response.data);
         }
         return response;
       },
       (err) => {
         console.log("请求响应报错", err);
         this.loadingInstance?.close();
         return err;
       }
     );
   }
 }
  • 结合 elementPlus 实现一个loading hook
  • 在根目录下新建 hooks 目录,用于存放自定义的 hooks
 // hooks/useLoading.js
 import { ElLoading } from "element-plus";
 ​
 const useLoadingHook = (text = "loading") => {
   const loadingInstance = ElLoading.service({
     text,
     background: "rgba(0, 0, 0, 0.7)"
   });
 ​
   const closeLoading = () => loadingInstance.close();
   return { loadingInstance, closeLoading };
 };
 ​
 export default useLoadingHook;
  • 实现基础请求方法,通过 Promise 返回请求结果
 request(config) {
   return new Promise((resolve, reject) => {
     this.instance
       .request(config)
       .then((res) => {
         resolve(res.data);
       })
       .catch((err) => {
         console.log("request err:", err);
         reject(err);
       });
   });
 }
  • 封装 getpost 请求
 get(config) {
   return this.request({ ...config, method: "get" });
 }
 ​
 // 以params格式传参使用
 post(config) {
   return this.request({ ...config, method: "post" });
 }
 ​
 // 以Json格式传参使用
 postJson(config) {
   return this.request({
     ...config,
     method: "post",
     headers: { "Content-Type": "application/json" }
   });
 }
  • 将封装的 request 实例暴露
 const { VITE_BASE_URL } = import.meta.env; // 根据环境加载不同的请求地址
 const request = new Request(VITE_BASE_URL, 2000);
 export default request;

基于封装的 request 实例,实现登录接口函数

  • 按照对应接口,将请求的函数写入到对应的模块中
 // service/modules/auth.js
 import request from "../request";
 ​
 export const login = (params = {}) => {
   return request.post({ url: "/login", params, showLoading: true });
 };
 ​
  • 通过 index 统一暴露
 export * from "./modules/home";
 export * from "./modules/auth";

使用定义好的请求函数

 import { login } from "@/service";
 ​
 login().then((res) => {
   console.log(res);
 });

vite+vue3项目从0到1搭建(3)---请求封装

转载自:https://juejin.cn/post/7266044346529349647
评论
请登录