ホームページ  >  記事  >  ウェブフロントエンド  >  axiosをカプセル化してvue3とtsでmock.jsを使う方法は何ですか?

axiosをカプセル化してvue3とtsでmock.jsを使う方法は何ですか?

王林
王林転載
2023-05-18 10:22:14900ブラウズ

    まえがき

    Axios と Ajax の区別に注意する必要があります。

    Ajax はテクノロジーの一般用語であり、技術的なコンテンツには、HTML または XHTML 、CSS、JavaScript、DOM、XML、XSLT、および最も重要な XMLHttpRequest が含まれます。XMLHttpRequest は、ブラウザとサーバーの間で非同期データ送信 (HTTP リクエスト) を使用し、ローカル リクエストを作成してローカル更新を実現するために使用されます。使用は XMLHttpRequest に基づいています。

    Axios は Promise ベースの HTTP ライブラリおよびサードパーティ ライブラリです

    主要なテクノロジ スタック: vue3、ts、axios、mock.js、 elementPlus

    1. axios の依存関係のインストールと処理

    1. 依存関係のインストール

    非同期ネットワーク リクエストの使用は、読み込み、メッセージ、その他のプロンプトから切り離すことはできません。 elementPlus で使用します;

    // 安装axios 
    npm install axios --save
     
    // 安装 elementPlus
    npm install element-plus --save

    2. Global axios package

    src ディレクトリ下の utils ディレクトリに、新しい request.ts を作成します。TS を使用するため、データ形式を事前に定義する必要があります:

    • リクエストデータの返却形式を定義します。事前に確認が必要です。

    • axios を定義します。基本的な構成情報

    • リクエスト インターセプタ: すべてのリクエストが最初に到着する場所。ここでリクエスト ヘッダー情報 (トークン、多言語など) をカスタマイズできます。

    • レスポンス インターセプタ: データが最初に到着する場所を返します。ここで例外情報を処理できます (例: コード 401 はログインにリダイレクトし、コード 500 はエラー メッセージを表示します)

    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(&#39;token&#39;) ?? &#39;&#39;;
                    return {
                        ...config,
                        headers: {
                            &#39;customToken&#39;: "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: &#39;Relogin&#39;,
                            type: &#39;warning&#39;
                        }).then(() => {
                            // 或者调用 logout 方法去处理
                            localStorage.setItem(&#39;token&#39;, &#39;&#39;);
                            location.href = &#39;/&#39;
                        })
                    }
                    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(&#39;请求失败&#39;);
                    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. 実際の使用方法

    src ディレクトリに api/index.ts を追加します

    • パラメータの型を定義しますrequest

    • 応答の特定のパラメータ タイプを定義します

    ここでは ts の名前空間を使用します。実際の開発では、多くのAPI は同じ名前でも意味が異なる場合があるため、定義には名前空間を使用します。

    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(&#39;Params and params in path can not empty!&#39;)
        // 这里因为是全局的一个info,根据路由地址去请求侧边栏,所需不用把地址写死
        return request.post<System.Sidebar>(params.path, { routeName: params.routeName })
    }

    Vue ファイルでの呼び出し

    <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 = &#39;/&#39; + routeName.replace(routeName[0], routeName[0].toLocaleLowerCase()) + &#39;Info&#39;
        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. 依存関係のインストールとモックの処理。 js

    1. 依存関係のインストール

    # 安装
    npm install mockjs --save

    ts で使用する場合、モジュールを shims-vue.d.ts ファイルにスローする必要があります。そうしないと、エラーが発生するという問題が発生します

    /* eslint-disable */
    declare module &#39;*.vue&#39; {
      import type { DefineComponent } from &#39;vue&#39;
      const component: DefineComponent<{}, {}, any>
      export default component
    }
     
    declare module &#39;mockjs&#39;;

    2. 新しいモックに必要なファイル

    axiosをカプセル化してvue3とtsでmock.jsを使う方法は何ですか?

    index.ts (mockjs グローバル設定ファイルに属します)、mockjs/javaScript/index を作成します。 ts (特定のデータ ファイル)、この 2 つは注意する必要がありますが、その他は注意する必要はありません

    1. 新しいmockjs /javaScript/index.ts (特定のデータ ファイル) を作成します

    ここでのデータは主にサイドバー内のデータであり、すべて固定されているため、データの生成にはmockjsのルールは使用されません。

    import { GlobalSidebar, Sidebar } from "../../sidebar";
     
    namespace InfoSidebar {
        export type InfoSidebarParams = {
            body: string,
            type: string,
            url: string
        }
    }
     
    const dataSource: Array<GlobalSidebar> = [
        {
            mainTitle: &#39;JavaScript基础问题梳理&#39;,
            mainSidebar: [
                {
                    id: 0,
                    hashId: &#39;This&#39;,
                    title: &#39;this指向&#39;,
                    routeName: &#39;JsBasic&#39;,
                    children: [
                        {
                            id: 1,
                            parentId: 0,
                            hashId: &#39;GlobalFunction&#39;,
                            title: &#39;全局函数&#39;
                        },
                        {
                            id: 2,
                            parentId: 0,
                            hashId: &#39;ObjectMethod&#39;,
                            title: &#39;对象方法&#39;
                        },
                        {
                            id: 3,
                            parentId: 0,
                            hashId: &#39;Constructor&#39;,
                            title: &#39;构造函数&#39;
                        },
                        {
                            id: 4,
                            parentId: 0,
                            hashId: &#39;SetTimeout&#39;,
                            title: &#39;定时器、回调函数&#39;
                        },
                        {
                            id: 5,
                            parentId: 0,
                            hashId: &#39;EventFunction&#39;,
                            title: &#39;事件函数&#39;
                        },
                        {
                            id: 6,
                            parentId: 0,
                            hashId: &#39;ArrowFunction&#39;,
                            title: &#39;箭头函数&#39;
                        },
                        {
                            id: 7,
                            parentId: 0,
                            hashId: &#39;CallApplyBind&#39;,
                            title: &#39;call、apply、bind&#39;
                        },
                    ]
                },
                {
                    id: 2,
                    hashId: &#39;DeepClone&#39;,
                    title: &#39;深拷贝和浅拷贝&#39;,
                    routeName: &#39;JsBasic&#39;,
                    children: []
                }
            ]
        },
    ];
     
    export default {
        name: &#39;jsBasicInfo&#39;,
        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
            }
        }
    }

    2. 新しいmockjs/index.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
    }

    3. main.tsを導入します

    import Mock from "mockjs";
    import jsBasicInfo from "./tpl/javaScript/index";
    const requestMethod = &#39;post&#39;;
    const BASE_URL = process.env.VUE_APP_BASE_API;
    const mocks = [jsBasicInfo];
     
    for (let i of mocks) {
        Mock.mock(BASE_URL + &#39;/&#39; + i.name, requestMethod, i.jsBasicInfo);
    }
     
    export default Mock

    3. 組み合わせて使用​​する

    は実際にはaxios

    import { createApp } from &#39;vue&#39;
    import App from &#39;./App.vue&#39;
     
    if(process.env.NODE_ENV == &#39;development&#39;){
        require(&#39;./mockjs/index&#39;)
    }
     
    const app = createApp(App);
    app.mount(&#39;#app&#39;);
    を呼び出したコード

    以上がaxiosをカプセル化してvue3とtsでmock.jsを使う方法は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。