功能

axios

用于与后端交互的组件

安装

1pnpm i -S axios

封装业务公共请求

apis/client/types.ts

 1import type { AxiosResponse, InternalAxiosRequestConfig } from "axios";
 2
 3// 业务接口结构
 4interface ApiResult<T = any> extends AxiosResponse {
 5  code: number;
 6  data: T;
 7  msg: string;
 8  error?: boolean;
 9  response?: AxiosResponse;
10}
11
12interface ApiRequestConfig extends InternalAxiosRequestConfig {
13  // 用户自定义配置
14  silent?: boolean;
15}
16
17export type { ApiResult, ApiRequestConfig };

封装公共请求拦截

apis/client/service.ts

  1import axios from "axios"; // 引入axios
  2import type { AxiosInstance, AxiosResponse, AxiosError } from "axios";
  3import type { ApiResult, ApiRequestConfig } from "./types";
  4import { ElMessage, ElMessageBox } from "element-plus";
  5import router from "@/router/index";
  6
  7class Service {
  8  service: AxiosInstance;
  9
 10  constructor(baseURL = "/", timeout = 30000) {
 11    this.service = axios.create({
 12      baseURL,
 13      timeout,
 14      headers: {
 15        "Content-type": "application/json",
 16      },
 17    });
 18    this.interceptors();
 19  }
 20  interceptors() {
 21    // http request 拦截器
 22    this.service.interceptors.request.use(
 23      (config: ApiRequestConfig) => {
 24        return config;
 25      },
 26      (error: AxiosError) => {
 27        ElMessage({
 28          showClose: true,
 29          message: error.message,
 30          type: "error",
 31        });
 32        return error;
 33      }
 34    );
 35    // http response 拦截器
 36    this.service.interceptors.response.use(
 37      (response: AxiosResponse) => {
 38        const resData = response.data as ApiResult;
 39        if (resData.code === 0) {
 40          return { data: resData.data, response } as any;
 41        } else {
 42          const { silent } = response.config as ApiRequestConfig;
 43          !silent &&
 44            ElMessage({
 45              showClose: true,
 46              message: response.data.msg || decodeURI(response.headers.msg),
 47              type: "error",
 48            });
 49          if (response.data.data && response.data.data.reload) {
 50            localStorage.clear();
 51            router.push({ name: "login", replace: true });
 52          }
 53          return { error: true, response };
 54        }
 55      },
 56      (error: AxiosError) => {
 57        if (!error.response) {
 58          ElMessageBox.confirm(
 59            `
 60              <p>检测到请求错误</p>
 61              <p>${error}</p>
 62              `,
 63            "请求报错",
 64            {
 65              dangerouslyUseHTMLString: true,
 66              distinguishCancelAndClose: true,
 67              confirmButtonText: "稍后重试",
 68              cancelButtonText: "取消",
 69            }
 70          ).then((r) => r.action.replace.name);
 71          return { error: true };
 72        }
 73
 74        switch (error.response.status) {
 75          case 500:
 76            ElMessageBox.confirm(
 77              `
 78              <p>检测到接口错误${error}</p>
 79              <p>错误码<span style="color:red"> 500 </span>:此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存</p>
 80              `,
 81              "接口报错",
 82              {
 83                dangerouslyUseHTMLString: true,
 84                distinguishCancelAndClose: true,
 85                confirmButtonText: "清理缓存",
 86                cancelButtonText: "取消",
 87              }
 88            ).then(() => {
 89              router.push({ name: "login", replace: true });
 90            });
 91            break;
 92          case 404:
 93            ElMessageBox.confirm(
 94              `
 95                <p>检测到接口错误${error}</p>
 96                <p>错误码<span style="color:red"> 404 </span>:此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格</p>
 97                `,
 98              "接口报错",
 99              {
100                dangerouslyUseHTMLString: true,
101                distinguishCancelAndClose: true,
102                confirmButtonText: "我知道了",
103                cancelButtonText: "取消",
104              }
105            ).then(() => {
106              router.push({ name: "login", replace: true });
107            });
108            break;
109        }
110
111        return {
112          error: true,
113          response: error.response,
114        };
115      }
116    );
117  }
118  get<T = any>(
119    url: string,
120    data?: T,
121    options?: Partial<ApiRequestConfig>
122  ): Promise<ApiResult<T>> {
123    return this.service.get(url, { params: data, ...options });
124  }
125  put<T = any, D = any>(
126    url: string,
127    data?: D,
128    options?: Partial<ApiRequestConfig>
129  ): Promise<ApiResult<T>> {
130    return this.service.put(url, data, options);
131  }
132  post<T = any, D = any>(
133    url: string,
134    data?: D,
135    options?: Partial<ApiRequestConfig>
136  ): Promise<ApiResult<T>> {
137    return this.service.post(url, data, options);
138  }
139  delete<T = any>(
140    url: string,
141    options?: Partial<ApiRequestConfig>
142  ): Promise<ApiResult<T>> {
143    return this.service.delete(url, options);
144  }
145}
146
147export default new Service();

MOCK

用于模拟后端的组件

安装

1pnpm i mockjs vite-plugin-mock --save-dev

vite.config.js

 1  plugins: [
 2    ...
 3    viteMockServe({
 4      // supportTs:false,
 5      // logger:false,
 6      mockPath: './src/mock/apis', //解析路径
 7      enable: true,
 8      watchFiles: true
 9    })
10  ],

编写一个 mock 接口

/src/mock/user.ts

 1import type { MockMethod } from 'vite-plugin-mock'
 2
 3export default [
 4  {
 5    url: '/api/login', // 注意,这里只能是string格式
 6    method: 'post',
 7    response: (req) => {
 8      if (req.body.username == 'admin') {
 9        return {
10          code: 0,
11          data: {
12            token: 'safdasdfas'
13          }
14        }
15      } else {
16        return {
17          code: 401,
18          msg: '用户名密码错误'
19        }
20      }
21    }
22  }
23] as MockMethod[] // 这里其实就是定义数据格式的,不了解的同学可以参考typescript的官方文档

scss

scss 是 css 的一种预处理语言

安装

1pnpm i sass sass-loader --save-dev

vite.config.js

 1  css: {
 2    // css预处理器
 3    preprocessorOptions: {
 4      scss: {
 5        // 引入 mixin.scss 这样就可以在全局中使用 mixin.scss中预定义的变量了
 6        // 给导入的路径最后加上 ;
 7        //additionalData: '@import "@/assets/main.scss";' //如果在main.ts中引入了,这里无需再次引用
 8      }
 9    }
10  },

使用

页面标签中加lang="scss"即可,如果没安装sass加该标签会语法报错

1<style lang="scss" scoped>
2...
3</style>

发布日期:2000-03-05 01:52 字数:720 用时 4分钟
tags:vue