最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3和ts封裝axios以及使用mock.js詳解

 更新時間:2023年02月17日 17:12:18   作者:程序員啊楠  
目前前端最流行的網(wǎng)絡(luò)請求庫還是axios,所以對axios的封裝很有必要,下面這篇文章主要給大家介紹了關(guān)于vue3和ts封裝axios以及使用mock.js的相關(guān)資料,文章通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

今天我們一起來看一看 vue3+ts如何優(yōu)雅的封裝axios,并結(jié)合 mock.js 實現(xiàn)敏捷開發(fā);

但是我們要注意區(qū)分 Axios 和 Ajax :

Ajax 是一種技術(shù)統(tǒng)稱,技術(shù)內(nèi)容包括:HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要的XMLHttpRequest,用于瀏覽器與服務(wù)器之間使用異步數(shù)據(jù)傳輸(HTTP 請求),做到局部請求以實現(xiàn)局部刷新,使用是基于 XMLHttpRequest 進(jìn)行使用;

  Axios 是 一個基于 promise 的 HTTP 庫,是一個是第三方庫

今天主要技術(shù)棧:vue3,ts,axios,mock.js,elementPlus

一、axios 的依賴安裝與處理  

1. 依賴安裝

使用異步網(wǎng)絡(luò)請求肯定離不開loading、message 等提示,今天我們配合 elementPlus 一起使用;

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

2. 全局 axios 封裝

 src 目錄下 utils 目錄下,新建 request.ts,因為使用的是TS,需要提前定義數(shù)據(jù)格式:

  • 定義請求數(shù)據(jù)返回的格式,需要提前確認(rèn)好
  • 定義 axios 基礎(chǔ)配置信息
  • 請求攔截器:所有請求最先到達(dá)的地方,我們可以在此自定義請求頭信息(比如:token、多語言等等)
  • 響應(yīng)攔截器:返回數(shù)據(jù)最先到達(dá)的地方,我們可以在此處理異常信息(比如:code為401重定向至登錄、code為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, // 服務(wù)器異常 server error
    LOGINTIMEOUT = 401, // 登錄超時 login timeout
    SUCCESS = 200, // 請求成功 request successfully
}
 
// axios 基礎(chǔ)配置
const config = {
    // 默認(rèn)地址,可以使用 process Node內(nèi)置的,項目根目錄下新建 .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)
            }
        );
 
        /**
         * 響應(yīng)攔截器
         * response -> { 響應(yīng)攔截器 } -> 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(() => {
                        // 或者調(diào)用 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("網(wǎng)絡(luò)連接失敗,請檢查網(wǎng)絡(luò)");
                    // 可以重定向至404頁面
                }
            }
 
        )
    }
 
    public handleCode = (code: number): void => {
        switch (code) {
            case 401:
                ElMessage.error("登陸失敗,請重新登錄");
                break;
            case 500:
                ElMessage.error("請求異常,請聯(lián)系管理員");
                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. 實際使用

src 目錄下新增 api/index.ts

  • 定義請求的參數(shù)類型
  • 定義響應(yīng)想具體參數(shù)類型

這里我們使用到ts 中的 namespace ,實際開發(fā)中我們很多 api 可能會出現(xiàn)相同名字不同含義,所以我們使用 namespace 進(jìn)行定義

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,根據(jù)路由地址去請求側(cè)邊欄,所需不用把地址寫死
    return request.post<System.Sidebar>(params.path, { routeName: params.routeName })
}

Vue 文件中調(diào)用

<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>

二、 mock.js 的依賴安裝與處理  

1. 安裝依賴

# 安裝
npm install mockjs --save

  在 ts 中使用時,我們需要現(xiàn)在 shims-vue.d.ts 文件中去拋出模塊,不然會出現(xiàn)引入報錯的問題

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

2. 新建 mock 所需的文件

 index.ts(屬于mockjs全局配置文件),mockjs/javaScript/index.ts(具體的數(shù)據(jù)文件),這兩個需要關(guān)注,別的不用關(guān)注

1. 新建 mockjs/javaScript/index.ts(具體的數(shù)據(jù)文件) 

因為我這里的數(shù)據(jù)主要是 側(cè)邊欄的數(shù)據(jù),都是固定好的,所以并沒有用到 mockjs 的規(guī)則生成數(shù)據(jù)

import { GlobalSidebar, Sidebar } from "../../sidebar";
 
namespace InfoSidebar {
    export type InfoSidebarParams = {
        body: string,
        type: string,
        url: string
    }
}
 
const dataSource: Array<GlobalSidebar> = [
    {
        mainTitle: 'JavaScript基礎(chǔ)問題梳理',
        mainSidebar: [
            {
                id: 0,
                hashId: 'This',
                title: 'this指向',
                routeName: 'JsBasic',
                children: [
                    {
                        id: 1,
                        parentId: 0,
                        hashId: 'GlobalFunction',
                        title: '全局函數(shù)'
                    },
                    {
                        id: 2,
                        parentId: 0,
                        hashId: 'ObjectMethod',
                        title: '對象方法'
                    },
                    {
                        id: 3,
                        parentId: 0,
                        hashId: 'Constructor',
                        title: '構(gòu)造函數(shù)'
                    },
                    {
                        id: 4,
                        parentId: 0,
                        hashId: 'SetTimeout',
                        title: '定時器、回調(diào)函數(shù)'
                    },
                    {
                        id: 5,
                        parentId: 0,
                        hashId: 'EventFunction',
                        title: '事件函數(shù)'
                    },
                    {
                        id: 6,
                        parentId: 0,
                        hashId: 'ArrowFunction',
                        title: '箭頭函數(shù)'
                    },
                    {
                        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
        }
    }
} 

Sidebar.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. 新建 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 { createApp } from 'vue'
import App from './App.vue'
 
if(process.env.NODE_ENV == 'development'){
    require('./mockjs/index')
}
 
const app = createApp(App);
app.mount('#app');

三、結(jié)合使用

實際上就是剛剛調(diào)用axios 的那一段代碼

<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>

總結(jié)

到此這篇關(guān)于vue3和ts封裝axios以及使用mock.js詳解的文章就介紹到這了,更多相關(guān)vue3 ts封裝axios使用mock.js內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 全局安裝 Vue cli3 和 繼續(xù)使用 Vue-cli2.x操作

    全局安裝 Vue cli3 和 繼續(xù)使用 Vue-cli2.x操作

    這篇文章主要介紹了全局安裝 Vue cli3 和 繼續(xù)使用 Vue-cli2.x操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Vue3中插槽slot的使用方法詳解

    Vue3中插槽slot的使用方法詳解

    在Vue?3中,插槽(slot)是一種強(qiáng)大的內(nèi)容分發(fā)API,它允許組件的模板開發(fā)者定義一種插槽,下面就跟隨小編一起來學(xué)習(xí)一下它的具體使用吧
    2024-11-11
  • 解決vue-cli輸入命令vue ui沒效果的問題

    解決vue-cli輸入命令vue ui沒效果的問題

    這篇文章主要介紹了解決vue-cli輸入命令vue ui沒效果的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • vue使用代理解決請求跨域問題詳解

    vue使用代理解決請求跨域問題詳解

    這篇文章主要為大家詳細(xì)介紹了vue使用代理解決請求跨域問題,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Vue中Rule的使用方式

    Vue中Rule的使用方式

    這篇文章主要介紹了Vue中Rule的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • vue全局引入scss樣式文件的過程記錄

    vue全局引入scss樣式文件的過程記錄

    css文件可以直接引入到main.js中,scss文件如果沒有scss特殊語法也可以直接引入index.js,只有scss文件中的特殊語法全局引入的時候無法顯示,所以需要特殊處理,下面這篇文章主要給大家介紹了關(guān)于vue全局引入scss樣式文件的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Vue跑馬燈marquee組件使用方法詳解

    Vue跑馬燈marquee組件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Vue跑馬燈marquee組件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Vue2.x-使用防抖以及節(jié)流的示例

    Vue2.x-使用防抖以及節(jié)流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節(jié)流的示例,幫助大家更好的理解和學(xué)習(xí)使用vue框架,感興趣的朋友可以了解下
    2021-03-03
  • Vue實現(xiàn)鎖屏功能的示例代碼

    Vue實現(xiàn)鎖屏功能的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Vue實現(xiàn)簡單的鎖屏功能,文中的示例代碼講解詳細(xì),具有一定的參考價值,需要的小伙伴可以了解一下
    2023-06-06
  • Vue.js組件實現(xiàn)選項卡以及切換特效

    Vue.js組件實現(xiàn)選項卡以及切換特效

    這篇文章主要為大家詳細(xì)介紹了Vue.js組件實現(xiàn)選項卡以及切換特效,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07

最新評論

什邡市| 临夏县| 塘沽区| 五家渠市| 随州市| 东山县| 大荔县| 乐平市| 小金县| 搜索| 巢湖市| 门头沟区| 开封县| 潍坊市| 黄龙县| 富川| 灵丘县| 安新县| 平泉县| 云南省| 盐源县| 扶绥县| 嘉鱼县| 汝阳县| 仪征市| 鞍山市| 旌德县| 乳山市| 伊川县| 始兴县| 华容县| 河间市| 安徽省| 阜城县| 天峨县| 镇安县| 务川| 龙州县| 图木舒克市| 营山县| 临武县|