Wie kapseln vue3 und ts Axios und verwenden mock.js

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

  1. Abhängigkeitsinstallation

  2. Globales Axios-Paket

  3. Tatsächliche Nutzung

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 

  3. main.ts-Import

3. In Kombination verwenden


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:

  1. Definieren Sie das Format der Anforderungsdatenrückgabe, die im Voraus bestätigt werden muss
  2. Definieren Sie grundlegende Axios-Konfigurationsinformationen
  3. Anfrage-Interceptor: Hier kommen alle Anfragen zuerst an, wo wir Anfrage-Header-Informationen anpassen können (z. B.: Token, mehrsprachig usw.)
  4. 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

  1. Definieren Sie den Parametertyp der Anfrage
  2. 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>

Supongo que te gusta

Origin blog.csdn.net/weixin_56650035/article/details/127467646
Recomendado
Clasificación