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

github仓库地址: github.com/Liangjiahon...

  • 安装 axios
shell 复制代码
 pnpm i axios
  • 在根目录下新建 service 文件夹,进行 axios 封装

目录结构如下

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

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

  • 初始化请求相关的信息
javascript 复制代码
 // 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;
  • 实现请求和响应拦截
javascript 复制代码
 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
javascript 复制代码
 // 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 返回请求结果
javascript 复制代码
 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 请求
javascript 复制代码
 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 实例暴露
javascript 复制代码
 const { VITE_BASE_URL } = import.meta.env; // 根据环境加载不同的请求地址
 const request = new Request(VITE_BASE_URL, 2000);
 export default request;

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

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

使用定义好的请求函数

javascript 复制代码
 import { login } from "@/service";
 ​
 login().then((res) => {
   console.log(res);
 });
相关推荐
我是小路路呀5 小时前
element级联选择器:已选中一个二级节点,随后又点击了一个一级节点(仅浏览,未确认选择),此时下拉框失去焦点并关闭
javascript·vue.js·elementui
程序员爱钓鱼5 小时前
Node.js 编程实战:文件读写操作
前端·后端·node.js
PineappleCoder5 小时前
工程化必备!SVG 雪碧图的最佳实践:ID 引用 + 缓存友好,无需手动算坐标
前端·性能优化
JIngJaneIL5 小时前
基于springboot + vue古城景区管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
敲敲了个代码5 小时前
隐式类型转换:哈基米 == 猫 ? true :false
开发语言·前端·javascript·学习·面试·web
澄江静如练_6 小时前
列表渲染(v-for)
前端·javascript·vue.js
JustHappy6 小时前
「chrome extensions🛠️」我写了一个超级简单的浏览器插件Vue开发模板
前端·javascript·github
Loo国昌6 小时前
Vue 3 前端工程化:架构、核心原理与生产实践
前端·vue.js·架构
sg_knight6 小时前
拥抱未来:ECMAScript Modules (ESM) 深度解析
开发语言·前端·javascript·vue·ecmascript·web·esm