1. 程式人生 > >設計vue3的請求實體工廠

設計vue3的請求實體工廠

# 設計一個vue3的請求實體工廠 [TOC] ## 描述 > PS: 這裡的方法是基於Vue的class寫法的,對於setup寫法不適用。 主要功能是建立一個具備一個請求完整封裝的例項,可以便捷的請求,取消請求,獲取資料和請求狀態等功能 下面是通過typescript和Vue實現,結合typescript的宣告,這個generateRequest方法才會得到昇華 ## 實現 實現分下面3個部分 > 1.構建一個基礎請求方法 > > 2.建立具體請求的方法 > > 3.generateRequest對請求的封裝 ### 構建一個基礎請求方法 這裡沒啥說的,直接上`axios`做一個簡單的封裝 `request.ts` ```typescript import axios from 'axios' const option = {...} export request = axios.create(option) ``` ### 建立具體請求的方法 #### 下面是對請求的宣告檔案 `xxx.d.ts` ```typescript // 對請求返回的請求體宣告 export class Result { /** code */ code?:number; /** data */ data?:T0; /** error_code */ error_code?:string; /** error_message */ error_message?:string; /** success */ success?:boolean; } // 文章介面返回data宣告 export interface ArticleData { id:number; title:string; cover_url:string; content:string; read_count:string; abstract:string; time:number; } ``` #### 下面是請求的定義 `api.ts` ``` typescript import { request } from './request' import { AxiosRequestConfig } from 'axios' import { Result, ArticleData } from './xxx' /** 獲取文章 */ export const getArticle = (id:number, config?:AxiosRequestConfig) => request.get(`/api/article?id=${id}`) ``` ### generateRequest對請求的封裝 這裡主要用到的知識點有: > 1.由對映型別進行推斷(對引數進行拆包) > > 2.對上下文的理解 > > 3.vue資料響應式機制 下面是一個基礎實現,還可以繼續封裝對業務場景有用的方法或屬性 #### 功能 - 具備響應式屬性:data(返回的資料)loading、isError、params(請求的引數) - 可以傳入資料處理的方法format - 設定data初始值initData - 取消請求的cancel方法 - 發起請求的run方法 `utils.ts` ``` typescript import axios, { AxiosPromise, AxiosRequestConfig } from 'axios'; interface GenerateRequestHook { data:T | undefined; run:(params?:K) => AxiosPromise; loading:boolean; isError:boolean; uid:number; cancel:((msg?:string) => void); params:K | undefined; } interface Config { config?:AxiosRequestConfig; format?:(data:any) => any; initData?:L; } let _uid = 0; /** * @description 返回請求的封裝實體的request,僅可以在class寫法的組建內使用 * @template T * @template K * @param {(params?:K, config?:AxiosRequestConfig) => AxiosPromise} reqFunc * @param {K} [params] * @param {Config} [config] * @returns {GenerateRequestHook} */ export const generateRequest = (reqFunc:(params?:K, config?:AxiosRequestConfig) => AxiosPromise, params?:K, config?:Config):GenerateRequestHook => { const uid = _uid++; const source = axios.CancelToken.source(); return { run: async function(_params?:K) { // eslint-disable-next-line @typescript-eslint/no-this-alias const self:GenerateRequestHook = this; if (!self || uid !== self.uid) { throw Error('[generateRequest] The context exception'); } try { self.isError = false; self.loading = true; if (_params) { self.params = _params; } const res = await reqFunc(_params || params, { cancelToken: source.token, ...config?.config, }); // 格式化返回資料 if (config?.format) { config.format(res.data); } self.data = res.data; return res; } catch (error) { self.data = config?.initData; self.isError = true; return Promise.reject(error); } finally { self.loading = false; } }, data: config?.initData, loading: false, isError: false, uid, cancel: source.cancel, params, }; }; ``` #### 使用demo ``` vue
``` 上面的this.articleReq會包含的屬性,我們可以直接使用`loading`、`data`、`isError,`而且這些屬性都是具備響應式的,而且data屬性是根據傳入`getArticle`推斷出資料型別,十分方便。可以通過cancel方法取消請求,run可以發起請求。 上面我的run方法內有這麼一段判斷,因為run方法內部是用了this來進行資料更新,讓屬性具備響應式。不過相對的限制就是不能修改this.articleReq.run呼叫時的上下文。這樣會導致獲取屬性異常。不過這個限制基本沒什麼影響,好處是大於壞處的。所以我給每個請求分配一個uid,用於判斷請求run方法的上下文是否一致。 ```typescript if (!self || uid !== self.uid) { throw Error('[generateRequest] The context exception'); } ``` ## 結語 上面`generateRequest`建立了一個具備響應式的請求例項,實現了從請求引數、請求資料都具備宣告,且可以直接在元件內使用具備響應式的屬性。目前來說還是挺方