post傳參方式,post請求只有一個參數時,學習Typescript 并使用單例模式 組合Vue+Element-ui 封裝 Axios
簡介
本文將實(shi)現在 Vue 框架中使用(yong) Typescript + Element-ui 以單例模式個性化封裝(zhuang) Axios, 滿足我們(men)項目的所需,留(liu)個贊再走吧(ba)
Typescript
什么是Typescript?
typescript 是 JavaScript 的(de)強類型版(ban)本。然后在(zai)編譯(yi)期(qi)去掉(diao)類型和(he)特有(you)語法(fa),生成純粹的(de) JavaScript 代碼(ma)。由于(yu)最終在(zai)瀏覽器中運行的(de)仍然是 JavaScript,所以 TypeScript 并不依賴于(yu)瀏覽器的(de)支持,也并不會(hui)帶來兼容性問(wen)題。
TypeScript 是 JavaScript 的超集,這意味著(zhu)他支持所有的 JavaScript 語法。并在(zai)此之上(shang)對 JavaScript 添(tian)加(jia)了一些擴(kuo)展(zhan),如(ru) class / interface / module 等。這樣會大(da)大(da)提升代碼的可(ke)閱讀性。
與(yu)此同(tong)時,TypeScript 也(ye)是 JavaScript ES6 的超集,Google 的 Angular 2.0 也(ye)宣布采用 TypeScript 進行開發(fa)。這(zhe)更是充分說明了這(zhe)是一門面向(xiang)未來并且腳踏(ta)實(shi)地(di)的語言。
為什么要學習 Typescript?
下面我們列(lie)出了(le)原(yuan)因,為什么(me)我們應該(gai)擁抱TypeScript:
完全(quan)的面(mian)向(xiang)對象(xiang),類和對象(xiang)。基于(yu)此,TypeScript將成為提高開發(fa)人員開發(fa)效率的利器,它很容易理(li)解和接受。
在編寫代碼的(de)(de)階段,TypeScript就(jiu)能夠找(zhao)到大部(bu)分的(de)(de)錯誤(wu),而JavaScript在這方面就(jiu)沒(mei)那(nei)么友好了。要(yao)知道,運行時錯誤(wu)越少(shao),你的(de)(de)程序的(de)(de)bug就(jiu)越少(shao)
相比JavaScript,TypeScript的重(zhong)構也更容易
強(qiang)類(lei)型(xing)語言的(de)優勢在于靜態類(lei)型(xing)檢查。概括來說主要包括以(yi)下(xia)幾點(dian):
靜態類型檢查
IDE 智能提示
代碼重構
可讀性
靜(jing)態類(lei)型檢查可以避免很多不必(bi)要的錯誤, 不用(yong)在調試(shi)的時候才發現(xian)問(wen)題
Axios
什么是 axios?
Axios 是一個(ge)基于 promise 的 HTTP 庫,可以用在(zai)瀏(liu)覽(lan)器和(he) node.js 中。
特性
從(cong)瀏覽(lan)器中創建 XMLHttpRequests
從 node.js 創建 http 請求
支持 Promise API
攔截請求和響應
轉換請求數(shu)據和響應數(shu)據
取消請求
自動轉換 JSON 數(shu)據
客戶(hu)端支持防御 XSRF
來看看 Axios 官方的例子
GET 的請求方式
// 為給定 ID 的 user 創建請求axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });// 上面的請求也可以這樣做axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
POST
axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
請求方法的別名
為方便起見(jian),為所有支持的(de)請求方法提供了別名
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
我(wo)們大致了(le)解了(le) Axios 以及一些常(chang)用的方法, 那(nei)接下來(lai)我(wo)們就開始進入正題吧
起手式項目
創建項目
$ vue create my-vue-typescript
上下鍵(jian)選擇,空格(ge)鍵(jian)確定
接(jie)下來是一些常規選(xuan)項
下(xia)面是詢(xun)問要(yao)不要(yao)記錄(lu)這次配置以(yi)便后面直接使用,我們選擇y
創建 Utils 文件夾以及 我們今天的主角 request.ts 文件
安裝所需包
Element-ui
$ npm i element-ui -S
qs
$ npm i qs -S
qs 是一個增加了一些安全性的查詢字符串解析和序列化字符串的庫
Axios
$ npm i axios -S
在此我(wo)不會為(wei)大家(jia)講(jiang)解太(tai)多(duo) Ts 的知識,但(dan)在開始之前想讓大家(jia)明白 Typescript 中的幾個點,不然沒法繼(ji)續下去
小知識講堂
類型注解
TypeScript里的類型注解是一種輕量(liang)級(ji)的為函數或變量(liang)添(tian)加約(yue)束(shu)的方式
# 我們指定了 hello 這個變量必須是 string 類型const hello: string = 'Hello World'# 我們指定了 greeter 傳入的 person 參數必須是 string 類型function greeter(person: string) { return "Hello, " + person;}
接口
在TypeScript里,只在兩(liang)(liang)個類型(xing)內部的(de)(de)結(jie)構兼(jian)容那么這(zhe)(zhe)兩(liang)(liang)個類型(xing)就是(shi)兼(jian)容的(de)(de)。 這(zhe)(zhe)就允許我們(men)在實(shi)現接口時(shi)候只要保證包含了(le)接口要求的(de)(de)結(jie)構就可(ke)以(yi),而不必明確地使用(yong) implements語句
interface IFamilyData { father: string mom: string son: string}function getFamily(family: IFamilyData) { return `爸爸${family.father},媽媽${family.mom},兒子${family.son}`}const family = { father: 'Jack', mom: 'Ruth', son: 'Bieber' }document.body.innerHTML = getFamily(family)
類
TypeScript支持(chi)JavaScript的新特性,比如(ru)支持(chi)基于類的面向(xiang)對象編(bian)程(cheng)
class Person{ // 增加兩個屬性 name:string age:number // 增加可以傳參的構造方法 constructor(name:string,age:number){ this.name = name this.age = age } // 增加一個自定義的普通的打印函數 print(){ return this.name + ':'' + this.age } // 使用上面創建的類 // var p = new Person() // 這里在使用上面的類時沒有傳遞參數是會報錯的,因為上面定義的 constructor 構造方法中存在參數,所以這里也一定要傳遞參數 var p = new Person('xiaochuan',22) alert(p.print())}
單例模式
最早接觸(chu)單例(li)模式是(shi)在(zai)學 PHP 的(de)時(shi)候,那個時(shi)候在(zai)還沒有使用(yong)框架 PHP 引入(ru) Mysql 的(de)時(shi)候,我都會把(ba) Mysql 封裝為一個單例(li)模式的(de)類(lei)
單(dan)例(li)(li)模式(shi)(shi)(Singleton),也叫單(dan)子模式(shi)(shi),是一(yi)(yi)種(zhong)常用(yong)的(de)(de)軟件(jian)設計模式(shi)(shi)。在應用(yong)這(zhe)個模式(shi)(shi)時(shi),單(dan)例(li)(li)對(dui)象(xiang)的(de)(de)類必(bi)須(xu)保證只(zhi)有一(yi)(yi)個實(shi)例(li)(li)存在。許多時(shi)候整個系統只(zhi)需要擁有一(yi)(yi)個的(de)(de)全局對(dui)象(xiang),這(zhe)樣有利于我(wo)們協調系統整體的(de)(de)行(xing)為。比如在某個服(fu)務(wu)器程序(xu)中,該服(fu)務(wu)器的(de)(de)配(pei)置(zhi)信息(xi)(xi)存放在一(yi)(yi)個文件(jian)中,這(zhe)些配(pei)置(zhi)數據由(you)一(yi)(yi)個單(dan)例(li)(li)對(dui)象(xiang)統一(yi)(yi)讀取(qu),然后服(fu)務(wu)進(jin)程中的(de)(de)其(qi)他對(dui)象(xiang)再通過(guo)這(zhe)個單(dan)例(li)(li)對(dui)象(xiang)獲取(qu)這(zhe)些配(pei)置(zhi)信息(xi)(xi)。這(zhe)種(zhong)方(fang)式(shi)(shi)簡化了在復雜環境下的(de)(de)配(pei)置(zhi)管(guan)理
優點
在(zai)單例(li)(li)模式(shi)中,活動的(de)單例(li)(li)只有(you)一(yi)個實例(li)(li),對單例(li)(li)類(lei)的(de)所(suo)有(you)實例(li)(li)化(hua)得到的(de)都(dou)是(shi)相同的(de)一(yi)個實例(li)(li)。這樣就(jiu) 防止其它對象對自己(ji)的(de)實例(li)(li)化(hua),確保所(suo)有(you)的(de)對象都(dou)訪問一(yi)個實例(li)(li)
單例模式具有一定(ding)的(de)伸縮性(xing),類自(zi)己來控制(zhi)實例化(hua)進程(cheng),類就在改變(bian)實例化(hua)進程(cheng)上(shang)有相應的(de)伸縮性(xing)
提供了對(dui)唯(wei)一(yi)實(shi)例的受控訪問
由于在系(xi)(xi)統內存(cun)中(zhong)只(zhi)存(cun)在一個對(dui)象(xiang),因此可以 節約系(xi)(xi)統資源,當 需(xu)要(yao)頻繁創建和銷毀的(de)對(dui)象(xiang)時(shi)單(dan)例模式無疑可以提高(gao)系(xi)(xi)統的(de)性能
允許可變數目的實例
避免對共享資源的(de)多重(zhong)占(zhan)用(yong)
缺點
不適用(yong)(yong)于變化的(de)對(dui)象(xiang),如(ru)果(guo)同一類型的(de)對(dui)象(xiang)總是要在(zai)不同的(de)用(yong)(yong)例場(chang)景發(fa)生變化,單例就(jiu)會引(yin)起數(shu)據(ju)的(de)錯誤,不能(neng)保存彼此(ci)的(de)狀態
由于單利模式中沒有抽象(xiang)層(ceng),因(yin)此單例類的擴展有很大的困(kun)難
單(dan)(dan)例類的(de)職(zhi)責過重,在一(yi)(yi)定程度上(shang)違背(bei)了“單(dan)(dan)一(yi)(yi)職(zhi)責原則”
濫用(yong)單(dan)例將(jiang)帶來(lai)一些(xie)負面問題,如(ru)為了(le)節(jie)省(sheng)資源將(jiang)數(shu)據(ju)庫連(lian)(lian)接池(chi)(chi)對(dui)象(xiang)設(she)計(ji)為的(de)(de)單(dan)例類(lei),可(ke)能會導致(zhi)共享(xiang)連(lian)(lian)接池(chi)(chi)對(dui)象(xiang)的(de)(de)程序(xu)過多(duo)而出(chu)現(xian)連(lian)(lian)接池(chi)(chi)溢出(chu);如(ru)果實(shi)例化的(de)(de)對(dui)象(xiang)長時(shi)間(jian)不(bu)被利(li)用(yong),系統會認為是(shi)垃(la)圾而被回(hui)收,這將(jiang)導致(zhi)對(dui)象(xiang)狀態的(de)(de)丟失
適用場景
單例模式(shi)只(zhi)允許創(chuang)建一(yi)個對(dui)象(xiang),因(yin)此(ci)節(jie)省內存,加快(kuai)對(dui)象(xiang)訪問速(su)度,因(yin)此(ci)對(dui)象(xiang)需要被公用(yong)的場(chang)合適合使(shi)用(yong),如多(duo)個模塊使(shi)用(yong)同一(yi)個數據源(yuan)連接對(dui)象(xiang)等等。如:
需(xu)要頻繁實例化然(ran)后銷毀的對象。
創建對象時耗時過多或者(zhe)耗資源(yuan)過多,但又經常(chang)用到的對象。
有狀態的(de)工(gong)具類(lei)對象。
頻(pin)繁訪問數據庫或文(wen)件的對象
實現思路:
一(yi)個(ge)類(lei)能返(fan)回對象(xiang)(xiang)一(yi)個(ge)引(yin)(yin)(yin)用(yong)(yong)(yong)(yong)(永(yong)遠是同一(yi)個(ge))和一(yi)個(ge)獲得該(gai)(gai)實(shi)(shi)例(li)的(de)方(fang)法(fa)(fa)(fa)(必(bi)須(xu)是靜(jing)(jing)態方(fang)法(fa)(fa)(fa),通常使用(yong)(yong)(yong)(yong)getInstance這(zhe)個(ge)名(ming) 稱);當我們(men)調(diao)用(yong)(yong)(yong)(yong)這(zhe)個(ge)方(fang)法(fa)(fa)(fa)時,如果類(lei)持(chi)有(you)的(de)引(yin)(yin)(yin)用(yong)(yong)(yong)(yong)不為空就返(fan)回這(zhe)個(ge)引(yin)(yin)(yin)用(yong)(yong)(yong)(yong),如果類(lei)保持(chi)的(de)引(yin)(yin)(yin)用(yong)(yong)(yong)(yong)為空就創建(jian)該(gai)(gai)類(lei)的(de)實(shi)(shi)例(li)并將實(shi)(shi)例(li)的(de)引(yin)(yin)(yin)用(yong)(yong)(yong)(yong)賦予(yu)該(gai)(gai)類(lei)保持(chi)的(de)引(yin)(yin)(yin)用(yong)(yong)(yong)(yong);同時我們(men) 還將該(gai)(gai)類(lei)的(de)構造(zao)函數(shu)定(ding)義為私有(you)方(fang)法(fa)(fa)(fa),這(zhe)樣其他處的(de)代碼(ma)就無法(fa)(fa)(fa)通過調(diao)用(yong)(yong)(yong)(yong)該(gai)(gai)類(lei)的(de)構造(zao)函數(shu)來實(shi)(shi)例(li)化該(gai)(gai)類(lei)的(de)對象(xiang)(xiang),只有(you)通過該(gai)(gai)類(lei)提供的(de)靜(jing)(jing)態方(fang)法(fa)(fa)(fa)來得到該(gai)(gai)類(lei)的(de)唯(wei)一(yi)實(shi)(shi)例(li)
開始
擼基礎結構
# public 公開的# protected 受保護的# private 私有的import http from 'http'import https from 'https'import axios, { AxiosResponse, AxiosRequestConfig, CancelTokenStatic } from 'axios'import { Message, MessageBox } from 'element-ui'import qs from 'qs'import { UserModule } from '@/store/modules/user'// 類名class Request { // 屬性 protected baseURL: any = process.env.VUE_APP_BASE_API protected service: any protected pending: Array<{ url: string, cancel: Function }> = [] protected CancelToken: CancelTokenStatic = axios.CancelToken protected axiosRequestConfig: AxiosRequestConfig = {} protected successCode: Array<Number> = [200, 201, 204] private static _instance: Request; // 構造函數 初始化工作 private constructor() { } // 唯一實例 public static getInstance() : Request {} protected requestConfig(): void {} protected interceptorsRequest() {} protected interceptorsResponse(): void {} protected removePending(config: any): void {} public async post(url: string, data: any = {}, config: object = {}) {} public async delete(url: string, config: object = {}) {} public async put(url: string, data: any = {}, config: object = {}) {} public async get(url: string, params: any = {}, config: object = {}) {} protected requestLog(request: any): void {} protected responseLog(response: any): void {}}export default Request.getInstance()
自定義實例默認值 requestConfig
從(cong)名字(zi)上我們就看的(de)出來這(zhe)是一個關于配置的(de)方法 小提示: void 表示沒有(you)返(fan)回值
protected requestConfig(): void { this.axiosRequestConfig = { // baseURL`將自動加在 `url` 前面,除非 `url` 是一個絕對 URL baseURL: this.baseURL, // `headers` 是即將被發送的自定義請求頭 headers: { timestamp: new Date().getTime(), 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' }, // transformRequest` 允許在向服務器發送前,修改請求數據 transformRequest: [function (data: any) { //對data進行任意轉換處理 return data; }], // `transformResponse` 在傳遞給 then/catch 前,允許修改響應數據 transformResponse: [function(data: AxiosResponse) { return data }], // `paramsSerializer` 是一個負責 `params` 序列化的函數 paramsSerializer: function(params: any) { return qs.stringify(params, { arrayFormat: 'brackets' }) }, // `timeout` 指定請求超時的毫秒數(0 表示無超時時間) // 如果請求話費了超過 `timeout` 的時間,請求將被中斷 timeout: 30000, // `withCredentials` 表示跨域請求時是否需要使用憑證 withCredentials: false, // `responseType` 表示服務器響應的數據類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' responseType: 'json', // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名稱 xsrfCookieName: 'XSRF-TOKEN', // `xsrfHeaderName` 是承載 xsrf token 的值的 HTTP 頭的名稱 xsrfHeaderName: 'X-XSRF-TOKEN', // `maxRedirects` 定義在 node.js 中 follow 的最大重定向數目 maxRedirects: 5, // `maxContentLength` 定義允許的響應內容的最大尺寸 maxContentLength: 2000, // `validateStatus` 定義對于給定的HTTP 響應狀態碼是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者設置為 `null` 或 `undefined`),promise 將被 resolve; 否則,promise 將被 rejecte validateStatus: function(status: number) { return status >= 200 && status < 300 }, // `httpAgent` 和 `httpsAgent` 分別在 node.js 中用于定義在執行 http 和 https 時使用的自定義代理。允許像這樣配置選項: // `keepAlive` 默認沒有啟用 httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }) } }
請求攔截器 interceptorsRequest
protected interceptorsRequest() { this.service.interceptors.request.use( (config: any) => { if (UserModule.token) { config.headers['authorization'] = UserModule.token } return config }, (error: any) => { return Promise.reject(error) } ) }
響應攔截器 `interceptorsResponse
protected interceptorsResponse(): void { this.service.interceptors.response.use( (response: any) => { if (this.successCode.indexOf(response.status) === -1) { Message({ message: response.data.message || 'Error', type: 'error', duration: 5 * 1000 }) if (response.data.code === 401) { MessageBox.confirm( '你已被登出,可以取消繼續留在該頁面,或者重新登錄', '確定登出', { confirmButtonText: '重新登錄', cancelButtonText: '取消', type: 'warning' } ).then(() => { UserModule.ResetToken() location.reload() }) } return Promise.reject(new Error(response.message || 'Error')) } else { return response.data } }, (error: any) => { Message({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) }
重復點擊取消上一次請求 removePending
protected removePending(config: any): void { for (let p in this.pending) { let item: any = p let list: any = this.pending[p] if (list.url === `${config.url}/${JSON.stringify(config.data)}&request_type=${config.method}`) { list.cancel() this.pending.splice(item, 1) } } }
響應 logs responseLog
protected responseLog(response: any): void { if (process.env.NODE_ENV === 'development') { const randomColor = `rgba(${Math.round(Math.random() * 255)},${Math.round( Math.random() * 255 )},${Math.round(Math.random() * 255)})` console.log( '%c┍------------------------------------------------------------------┑', `color:${randomColor};` ) console.log('| 請求地址:', response.config.url) console.log('| 請求參數:', qs.parse(response.config.data)) console.log('| 返回數據:', response.data) console.log( '%c┕------------------------------------------------------------------┙', `color:${randomColor};` ) } }
請求方式 POST GET PUT DELETE
public async post(url: string, data: any = {}, config: object = {}) { try { const result = await this.service.post(url, qs.stringify(data), config) return result.data } catch (error) { console.error(error) } } public async delete(url: string, config: object = {}) { try { await this.service.delete(url, config) } catch (error) { console.error(error) } }...
整合代碼
import http from 'http'import https from 'https'import axios, { AxiosResponse, AxiosRequestConfig, CancelTokenStatic } from 'axios'import { Message, MessageBox } from 'element-ui'import qs from 'qs'import { UserModule } from '@/store/modules/user'class Request { protected baseURL: any = process.env.VUE_APP_BASE_API protected service: any = axios protected pending: Array<{ url: string, cancel: Function }> = [] protected CancelToken: CancelTokenStatic = axios.CancelToken protected axiosRequestConfig: AxiosRequestConfig = {} protected successCode: Array<Number> = [200, 201, 204] private static _instance: Request; constructor() { this.requestConfig() this.service = axios.create(this.axiosRequestConfig) this.interceptorsRequest() this.interceptorsResponse() } public static getInstance() : Request { // 如果 instance 是一個實例 直接返回, 如果不是 實例化后返回 this._instance || (this._instance = new Request()) return this._instance } protected requestConfig(): void { this.axiosRequestConfig = { baseURL: this.baseURL, headers: { timestamp: new Date().getTime(), 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' }, transformRequest: [obj => qs.stringify(obj)], transformResponse: [function(data: AxiosResponse) { return data }], paramsSerializer: function(params: any) { return qs.stringify(params, { arrayFormat: 'brackets' }) }, timeout: 30000, withCredentials: false, responseType: 'json', xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxRedirects: 5, maxContentLength: 2000, validateStatus: function(status: number) { return status >= 200 && status < 500 }, httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }) } } protected interceptorsRequest() { this.service.interceptors.request.use( (config: any) => { this.removePending(config) config.CancelToken = new this.CancelToken((c: any) => { this.pending.push({ url: `${config.url}/${JSON.stringify(config.data)}&request_type=${config.method}`, cancel: c }) }) if (UserModule.token) { config.headers['authorization'] = UserModule.token } this.requestLog(config) return config }, (error: any) => { return Promise.reject(error) } ) } protected interceptorsResponse(): void { this.service.interceptors.response.use( (response: any) => { this.responseLog(response) this.removePending(response.config) if (this.successCode.indexOf(response.status) === -1) { Message({ message: response.data.message || 'Error', type: 'error', duration: 5 * 1000 }) if (response.data.code === 401) { MessageBox.confirm( '你已被登出,可以取消繼續留在該頁面,或者重新登錄', '確定登出', { confirmButtonText: '重新登錄', cancelButtonText: '取消', type: 'warning' } ).then(() => { UserModule.ResetToken() location.reload() }) } return Promise.reject(new Error(response.message || 'Error')) } else { return response.data } }, (error: any) => { Message({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) } protected removePending(config: any): void { for (let p in this.pending) { let item: any = p let list: any = this.pending[p] if (list.url === `${config.url}/${JSON.stringify(config.data)}&request_type=${config.method}`) { list.cancel() console.log('=====', this.pending) this.pending.splice(item, 1) console.log('+++++', this.pending) } } } public async post(url: string, data: any = {}, config: object = {}) { try { const result = await this.service.post(url, qs.stringify(data), config) return result.data } catch (error) { console.error(error) } } public async delete(url: string, config: object = {}) { try { await this.service.delete(url, config) } catch (error) { console.error(error) } } public async put(url: string, data: any = {}, config: object = {}) { try { await this.service.put(url, qs.stringify(data), config) } catch (error) { console.error(error) } } public async get(url: string, parmas: any = {}, config: object = {}) { try { await this.service.get(url, parmas, config) } catch (error) { console.error(error) } } protected requestLog(request: any): void { } protected responseLog(response: any): void { if (process.env.NODE_ENV === 'development') { const randomColor = `rgba(${Math.round(Math.random() * 255)},${Math.round( Math.random() * 255 )},${Math.round(Math.random() * 255)})` console.log( '%c┍------------------------------------------------------------------┑', `color:${randomColor};` ) console.log('| 請求地址:', response.config.url) console.log('| 請求參數:', qs.parse(response.config.data)) console.log('| 返回數據:', response.data) console.log( '%c┕------------------------------------------------------------------┙', `color:${randomColor};` ) } }}export default Request.getInstance()
使用方法
import Request from '@/utils/request'import { ADMIN_LOGIN_API, ADMIN_USER_INFO_API } from '@/api/interface'interface ILoginData { username: string password: string}export const login = (params: ILoginData) => Request.post(ADMIN_LOGIN_API, params)export const getUserInfo = () => Request.get(ADMIN_USER_INFO_API)
結尾
各位大哥大姐留個贊吧(ba) O(∩_∩)O哈哈~ 到此就結(jie)束(shu)了,我也是第一次學習 ts 并且 封(feng)裝 axios 寫的(de)不好,下方留言(yan)指出,謝(xie)謝(xie)。