簡介

由於想找個 UI 的 Framework 套入,並可以支援 Vue3TypeScript ,最後就找到 Naive UI 的套件,那也順便看了一下其它人是如何使用該套件的,就找到了 Naive UI Admin 這個官方分享的免費第三方樣版。

其中就看了一下該樣版是如何把 Axios 套入並使用,也一拼將其整理一下,並試著實作。

開發

安裝 Axios

透過喜歡的方式進行安裝 Axios

1
2
3
npm install axios
# or
pnpm install axios

封裝 Axios

建立 ./src/utils/http/axios 的資料夾,用來存放 Axios 調用的相關程式

建立常用的 Utils

建立 ./src/utils/index.ts

@vueuse/core 需先安裝 VueUse

1
2
3
4
5
6
7
8
9
10
import { isObject } from '@vueuse/core'

// 深度 Copy 確保不參考到同一個記憶體
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
let key: string
for (key in target)
src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key])

return src
}

建立可讀性的 Enums

建立 ./src/enums/httpEnum.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @description: Request Verb
*/
export enum RequestEnum {
GET = 'GET',
POST = 'POST',
PATCH = 'PATCH',
PUT = 'PUT',
DELETE = 'DELETE',
}

/**
* @description: Content Type
*/
export enum ContentTypeEnum {
// json
JSON = 'application/json;charset=UTF-8',
// json
TEXT = 'text/plain;charset=UTF-8',
// form-data
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
// form-data upload
FORM_DATA = 'multipart/form-data;charset=UTF-8',
}

建立 Types 聲明

建立 ./src/utils/http/axios/types.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { AxiosRequestConfig } from 'axios';

// 繼承 AxiosRequestConfig 並添加自訂的條件,在 Axios 調用或攔截器(Interceptors)中可以使用
export interface CreateAxiosOptions extends AxiosRequestConfig {
requestOptions?: RequestOptions; // customize setting
}

// 自訂 Axios Request 觸發時的一些參數
export interface RequestOptions {
}

// 定義回傳的 res.data 格式,這部份要配合 API 的回傳格式,方便取值
export interface Result<T = any> {
code: number;
type?: 'success' | 'error' | 'warning';
message: string;
result?: T;
}

透過 Class 封裝 Axios 實例

建立 ./src/utils/http/axios/Axios.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import axios from 'axios'
import type { CreateAxiosOptions, RequestOptions, Result } from './types'
import { deepMerge } from '~/utils'

export class LKAxios {
// 建立 Axios 實例
private axiosInstance: AxiosInstance
// 初使化的 Axios Options
private options: CreateAxiosOptions
// Initial 該 Class 時呼叫
constructor(options: CreateAxiosOptions) {
this.options = options
this.axiosInstance = axios.create(options)
}

/*
* 調用 Axios.request
* config Axios 支援的設定值
* option 調用時的額外參數
*/
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
// 要丟入 Axios 的參數,從傳入值先 Copy 出來
const conf: CreateAxiosOptions = deepMerge({}, config)
// 把初使化的額外參數取出
const { requestOptions } = this.options
// 用調用時的額外參數去蓋掉初使化的(保留初使化中未重覆的)
const opt: RequestOptions = Object.assign({}, requestOptions, options)
conf.requestOptions = opt

return new Promise((resolve, reject) => {
this.axiosInstance
.request<any, AxiosResponse<Result>>(conf)
.then((res: AxiosResponse<Result>) => {
resolve(res as unknown as Promise<T>)
})
})
}
}

建立調用 Axios 入口

建立 ./src/utils/http/axios/index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { ContentTypeEnum } from '~/enums/httpEnum'
import { deepMerge } from '~/utils'
import { LKAxios } from './Axios'
import type { CreateAxiosOptions } from './types'

function createAxios(opt?: Partial<CreateAxiosOptions>) {
return new LKAxios(
deepMerge({
baseURL: '',
timeout: 10 * 1000,
headers: { 'Content-Type': ContentTypeEnum.JSON },
requestOptions: {
}
}, opt || {}))
}

// 公開讓其它頁面去調用
export const http = createAxios()

測試

在任意的 .vue 檔案中

1
2
3
4
5
6
7
8
<script setup lang="ts">
import { http } from '~/utils/http/axios'

http.request({ url: '/api/v1/test' }).then((res) => {
console.log(res.data)
})
</script>

參考

Naive UI Third-Party Libraries
Naive UI Admin
Axios
Vitesse
Sample Code Download