Werfen wir heute einen Blick darauf, wie vue3+ts axios elegant kapselt und mock.js kombiniert, um eine agile Entwicklung zu erreichen;
Aber wir sollten auf die Unterscheidung zwischen Axios und Ajax achten:
Ajax ist ein Sammelbegriff für Technologien, darunter: HTML bzw. XHTML, CSS, JavaScript, DOM, XML, XSLT und das wichtigste XMLHttpRequest, mit dem eine asynchrone Datenübertragung (HTTP-Requests) zwischen Browsern und Servern partielle Requests erreicht werden teilweise Aktualisierung, die Verwendung basiert auf XMLHttpRequest;
Axios ist eine Promise-basierte HTTP-Bibliothek und eine Bibliothek eines Drittanbieters
Der heutige Haupttechnologie-Stack: vue3, ts, axios, mock.js, elementPlus
Inhaltsverzeichnis
1. Installation und Verarbeitung von Axios-Abhängigkeiten
2. Installation und Verarbeitung von Abhängigkeiten von mock.js
1. Installieren Sie Abhängigkeiten
2. Erstellen Sie die erforderlichen Dateien für das Mock
1. Erstellen Sie eine neue mockjs/javaScript/index.ts (spezifische Datendatei)
2. Erstellen Sie eine neue mockjs/index.ts
1. Installation und Verarbeitung von Axios-Abhängigkeiten
1. Abhängigkeitsinstallation
Die Verwendung von asynchronen Netzwerkanfragen muss untrennbar mit Lade-, Nachrichten- und anderen Eingabeaufforderungen verbunden sein.Heute verwenden wir es mit elementPlus;
// 安装axios
npm install axios --save
// 安装 elementPlus
npm install element-plus --save
2. Globales Axios-Paket
Erstellen Sie im utils-Verzeichnis unter dem src-Verzeichnis eine neue request.ts Da TS verwendet wird, muss das Datenformat im Voraus definiert werden:
- Definieren Sie das Format der Anforderungsdatenrückgabe, die im Voraus bestätigt werden muss
- Definieren Sie grundlegende Axios-Konfigurationsinformationen
- Anfrage-Interceptor: Hier kommen alle Anfragen zuerst an, wo wir Anfrage-Header-Informationen anpassen können (z. B.: Token, mehrsprachig usw.)
- Response Interceptor: Gibt den Ort zurück, an dem die Daten zuerst ankommen, wo wir Ausnahmeinformationen behandeln können (z. B.: Code 401 leitet zur Anmeldung weiter, Code 500 führt zu einer Fehlermeldung)
import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import { ElMessage, ElLoading, ElMessageBox } from "element-plus";
// response interface { code, msg, success }
// 不含 data
interface Result {
code: number,
success: boolean,
msg: string
}
// request interface,包含 data
interface ResultData<T = any> extends Result {
data?: T
}
enum RequestEnums {
TIMEOUT = 10000, // 请求超时 request timeout
FAIL = 500, // 服务器异常 server error
LOGINTIMEOUT = 401, // 登录超时 login timeout
SUCCESS = 200, // 请求成功 request successfully
}
// axios 基础配置
const config = {
// 默认地址,可以使用 process Node内置的,项目根目录下新建 .env.development
baseURL: process.env.VUE_APP_BASE_API as string,
timeout: RequestEnums.TIMEOUT as number, // 请求超时时间
withCredentials: true, // 跨越的时候允许携带凭证
}
class Request {
service: AxiosInstance;
constructor(config: AxiosRequestConfig) {
// 实例化 serice
this.service = axios.create(config);
/**
* 请求拦截器
* request -> { 请求拦截器 } -> server
*/
this.service.interceptors.request.use(
(config: AxiosRequestConfig) => {
const token = localStorage.getItem('token') ?? '';
return {
...config,
headers: {
'customToken': "customBearer " + token
}
}
},
(error: AxiosError) => {
// 请求报错
Promise.reject(error)
}
);
/**
* 响应拦截器
* response -> { 响应拦截器 } -> client
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const { data, config } = response;
if (data.code === RequestEnums.LOGINTIMEOUT) {
// 表示登录过期,需要重定向至登录页面
ElMessageBox.alert("Session expired", "System info", {
confirmButtonText: 'Relogin',
type: 'warning'
}).then(() => {
// 或者调用 logout 方法去处理
localStorage.setItem('token', '');
location.href = '/'
})
}
if (data.code && data.code !== RequestEnums.SUCCESS) {
ElMessage.error(data);
return Promise.reject(data);
}
return data
},
(error: AxiosError) => {
const { response } = error;
if (response) {
this.handleCode(response.status);
}
if (!window.navigator.onLine) {
ElMessage.error("网络连接失败,请检查网络");
// 可以重定向至404页面
}
}
)
}
public handleCode = (code: number): void => {
switch (code) {
case 401:
ElMessage.error("登陆失败,请重新登录");
break;
case 500:
ElMessage.error("请求异常,请联系管理员");
break;
default:
ElMessage.error('请求失败');
break;
}
}
// 通用方法封装
get<T>(url: string, params?: object): Promise<ResultData<T>> {
return this.service.get(url, { params });
}
post<T>(url: string, params?: object): Promise<ResultData<T>> {
return this.service.post(url, params);
}
put<T>(url: string, params?: object): Promise<ResultData<T>> {
return this.service.put(url, params);
}
delete<T>(url: string, params?: object): Promise<ResultData<T>> {
return this.service.delete(url, { params });
}
}
export default new Request(config)
3. Tatsächliche Nutzung
Fügen Sie api/index.ts im src-Verzeichnis hinzu
- Definieren Sie den Parametertyp der Anfrage
- Definieren Sie die Reaktion auf den spezifischen Parametertyp
Hier verwenden wir den Namensraum in ts. In der tatsächlichen Entwicklung haben viele unserer APIs möglicherweise denselben Namen, aber unterschiedliche Bedeutungen, daher verwenden wir den Namensraum zum Definieren
import request from "@/utils/request";
namespace User {
// login
export interface LoginForm {
userName: string,
password: string
}
}
export namespace System {
export interface Info {
path: string,
routeName: string
}
export interface ResponseItem {
code: number,
items: Array<Sidebar>,
success: boolean
}
export interface Sidebar {
id: number,
hashId: string | number,
title: string,
routeName: string,
children: Array<SidebarItem>,
}
export interface SidebarItem {
id: number,
parentId: number,
hashId: string | number,
title: string,
}
}
export const info = (params: System.Info) => {
// response
if (!params || !params.path) throw new Error('Params and params in path can not empty!')
// 这里因为是全局的一个info,根据路由地址去请求侧边栏,所需不用把地址写死
return request.post<System.Sidebar>(params.path, { routeName: params.routeName })
}
Wird in der Vue-Datei aufgerufen
<script lang="ts" setup name="Sidebar">
import { ref, reactive, onBeforeMount } from "vue"
import { info } from "@/api"
import { useRoute } from "vue-router"
const route = useRoute();
let loading = ref<boolean>(false);
let sidebar = ref<any>({});
const _fetch = async (): Promise<void> => {
const routeName = route.name as string;
const path = '/' + routeName.replace(routeName[0], routeName[0].toLocaleLowerCase()) + 'Info'
try {
loading.value = true;
const res = await info({ path, routeName });
if (!res || !res.data) return;
sidebar.value = res.data;
} finally {
loading.value = false
}
}
onBeforeMount(() => {
_fetch();
})
</script>
2. Installation und Verarbeitung von Abhängigkeiten von mock.js
1. Installieren Sie Abhängigkeiten
# 安装
npm install mockjs --save
Wenn wir es in ts verwenden, müssen wir das Modul in die Datei shims-vue.d.ts werfen, da sonst ein Problem mit der Einführung eines Fehlers auftritt
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
declare module 'mockjs';
2. Erstellen Sie die erforderlichen Dateien für das Mock
index.ts (gehört zur globalen Konfigurationsdatei von mockjs), mockjs/javaScript/index.ts (spezifische Datendatei), diese beiden müssen beachtet werden, andere müssen nicht beachtet werden
1. Erstellen Sie eine neue mockjs/javaScript/index.ts (spezifische Datendatei)
Da die Daten hier hauptsächlich die Daten der Seitenleiste sind, die festgelegt sind, werden die Regeln von mockjs nicht zum Generieren von Daten verwendet
import { GlobalSidebar, Sidebar } from "../../sidebar";
namespace InfoSidebar {
export type InfoSidebarParams = {
body: string,
type: string,
url: string
}
}
const dataSource: Array<GlobalSidebar> = [
{
mainTitle: 'JavaScript基础问题梳理',
mainSidebar: [
{
id: 0,
hashId: 'This',
title: 'this指向',
routeName: 'JsBasic',
children: [
{
id: 1,
parentId: 0,
hashId: 'GlobalFunction',
title: '全局函数'
},
{
id: 2,
parentId: 0,
hashId: 'ObjectMethod',
title: '对象方法'
},
{
id: 3,
parentId: 0,
hashId: 'Constructor',
title: '构造函数'
},
{
id: 4,
parentId: 0,
hashId: 'SetTimeout',
title: '定时器、回调函数'
},
{
id: 5,
parentId: 0,
hashId: 'EventFunction',
title: '事件函数'
},
{
id: 6,
parentId: 0,
hashId: 'ArrowFunction',
title: '箭头函数'
},
{
id: 7,
parentId: 0,
hashId: 'CallApplyBind',
title: 'call、apply、bind'
},
]
},
{
id: 2,
hashId: 'DeepClone',
title: '深拷贝和浅拷贝',
routeName: 'JsBasic',
children: []
}
]
},
];
export default {
name: 'jsBasicInfo',
jsBasicInfo(params: InfoSidebar.InfoSidebarParams) {
const param = JSON.parse(params.body)
if (!param) throw new Error("Params can not empty!");
const data = dataSource.find((t: GlobalSidebar) => {
return t.mainSidebar.filter((x: Sidebar) => {
return x.routeName === param.routeName
})
})
return {
data,
success: true,
code: 200
}
}
}
Seitenleiste.ts
/**
* @param { number } id Unique value
* @param { string } hashId href Unique value
* @param { string } title show current title
* @param { string } routeName page find data
*/
interface GlobalSidebar {
mainTitle: string,
mainSidebar: Array<Sidebar>
}
interface Sidebar {
id: number,
hashId: string | number,
title: string,
routeName: string,
children: Array<SidebarItem>,
}
interface SidebarItem {
id: number,
parentId: number,
hashId: string | number,
title: string,
}
export {
GlobalSidebar,
Sidebar,
SidebarItem
}
2. Erstellen Sie eine neue mockjs/index.ts
import Mock from "mockjs";
import jsBasicInfo from "./tpl/javaScript/index";
const requestMethod = 'post';
const BASE_URL = process.env.VUE_APP_BASE_API;
const mocks = [jsBasicInfo];
for (let i of mocks) {
Mock.mock(BASE_URL + '/' + i.name, requestMethod, i.jsBasicInfo);
}
export default Mock
3. main.ts-Import
import { createApp } from 'vue'
import App from './App.vue'
if(process.env.NODE_ENV == 'development'){
require('./mockjs/index')
}
const app = createApp(App);
app.mount('#app');
3. In Kombination verwenden
Tatsächlich ist es das Stück Code, das gerade Axios aufgerufen hat
<script lang="ts" setup name="Sidebar">
import { ref, reactive, onBeforeMount } from "vue"
import { info } from "@/api"
import { useRoute } from "vue-router"
const route = useRoute();
let loading = ref<boolean>(false);
let sidebar = ref<any>({});
const _fetch = async (): Promise<void> => {
const routeName = route.name as string;
const path = '/' + routeName.replace(routeName[0], routeName[0].toLocaleLowerCase()) + 'Info'
try {
loading.value = true;
const res = await info({ path, routeName });
if (!res || !res.data) return;
sidebar.value = res.data;
} finally {
loading.value = false
}
}
onBeforeMount(() => {
_fetch();
})
</script>