【axios】Vue项目中封装和使用axios

在之前我们讲过axios的基本使用方法【axios】axios的基本使用,在实际的Vue项目中,我们并不使用这种方法。当时还未实现项目的规范化,没有严格划分组件和模块,只是把所有东西都写在一个html文件中,现在我们要从前端工程化的角度来看如何使用axios。

零、准备工作

假设我们有一个Vue项目,App根组件中包含一个Left组件和一个Right组件,Left组件中有一个按钮,点击后发送GET请求。Right组件中有一个按钮,点击后发送POST请求。基本页面构成如下:
在这里插入图片描述

首先需要安装axios包,后续才可以在项目中使用axios。在终端执行npm i axios -S,即可把axios安装到项目中。

一、在需要发送请求的.vue组件中导入axios并使用

Left组件的script标签内容:

<script>
// 导入axios模块
import axios from 'axios'

export default {
  data() {
    return {
      bookList: {}
    }
  },
  methods: {
  	// 点击事件
  	// <button @click="getInfo">发送GET请求</button>
    async getInfo() {
      const { data: res } = await axios.get('http://www.liulongbin.top:3006/api/getbooks')
      console.log(res)
      // 一般把请求回来的数据转存到data中
      this.bookList = res
    }
  }
}
</script>

Right组件的script标签内容:

<script>
// 导入axios模块
import axios from 'axios'

export default {
  methods: {
  	// 点击事件
  	// <button @click="postInfo">发送POST请求</button>
    async postInfo() {
      const { data: res } = await axios.post('http://www.liulongbin.top:3006/api/post', { name: 'zs', age: 20 })
      console.log(res)
      // 不再演示数据转存到data的过程
    }
  }
}
</script>

在这里插入图片描述
均可以成功请求,但是这种方法的缺点是:每使用一次axios,就要导入一次,只要这个.vue组件使用了axios,就需要导入axios模块,各组件之间不能互相使用(不通用),比较麻烦。因此我们希望axios全局可用

二、把axios挂载到Vue原型上并配置请求根路径

(1) 因为我们希望axios 全局可用,所以需要在 main.js文件中进行相应配置,步骤如下:

  1. 导入 axios 模块
  2. 将 axios 挂载到 Vue 原型上。
import Vue from 'vue'
import App from './App.vue'

// 1.导入axios模块
import axios from 'axios'

Vue.config.productionTip = false

// 2.将axios挂载到Vue原型上
Vue.prototype.$http = axios

new Vue({
  render: h => h(App)
}).$mount('#app')

【注意】将axios挂载到Vue原型上时,其中$http的名字是任意的,表示我们在Vue原型上挂载了一个名为$http的属性(方法),它的值为axios。习惯上,我们都把这个属性命名为$http

(2) 为了简化.vue组件实例的调用,可以配置一个请求根路径,之后使用时只需要传入根路径之后的部分即可。

import Vue from 'vue'
import App from './App.vue'

// 1.导入axios模块
import axios from 'axios'

Vue.config.productionTip = false

// 3.配置请求根路径
axios.defaults.baseURL = 'http://www.liulongbin.top:3006'
// 2.将axios挂载到Vue原型上
Vue.prototype.$http = axios

new Vue({
  render: h => h(App)
}).$mount('#app')

(3)在组件中的使用方法:

  1. 不再需要导入axios模块,直接删除导入代码
  2. 每一个.vue组件都可以看成是一个Vue实例,因为Vue原型上挂载了一个名为$http的属性,而.vue组件又是一个Vue实例,所以可以通过this.$http拿到axios,然后就可以正常使用了。
  3. 由于配置了请求根路径,所以GET/POST请求的第一个参数,直接传入根路径之后的部分即可。

Left组件的script标签内容:

<script>
// 不再需要导入axios模块,直接删除导入代码
export default {
  data() {
    return {
      bookList: {}
    }
  },
  methods: {
    async getInfo() {
      const { data: res } = await this.$http.get('/api/getbooks')
      console.log(res)
      // 一般把请求回来的数据转存到data中
      this.bookList = res
    }
  }
}
</script>

Right组件的script标签内容:

<script>
export default {
  methods: {
    async postInfo() {
      const { data: res } = await this.$http.post('/api/post', { name: 'zs', age: 20 })
      console.log(res)
      // 不再演示数据转存到data的过程
    }
  }
}
</script>

【缺点】:请求数据的代码复用性差,如果不同的组件需要请求同一份数据,每请求一次,就要写一次请求函数。

三、封装一个拿到axios的模块,并封装请求数据的API

1.封装axios模块

在和src目录同级的地方,新建一个utils文件夹,表示用到的工具,在里面新建一个request.js文件,这个就是封装axios的模块。谁需要用到这个根路径去请求数据,谁就导入这个模块。

request.js文件的内容:

// 导入axios
import axios from 'axios'

// 通过axios.create方法创建一个axios实例,用request接收
const request = axios.create({
  // 指定请求的根路径
  baseURL: 'http://www.liulongbin.top:3006'
})

export default request

使用方法(以Left组件为例):

<script>
// 导入request模块
import request from '@/utils/request.js'

export default {
  data() {
    return {
      bookList: {}
    }
  },
  methods: {
    async getInfo() {
      // 假设需要传一个参数,这里的参数是假的,演示用
      const { data: res } = await request.get('/api/getbooks', {
        params: { id: 1 }
      })
      console.log(res)
      // 一般把请求回来的数据转存到data中
      this.bookList = res
    }
  }
}
</script>

【拓展】一个项目中可以封装多个axios模块,如果需要用到多个不同的请求根路径,那么每一个根路径封装一个对应的axios模块,然后各模块之间互不相同,互不影响。

但是这个时候还是没有解决代码复用性低的问题,请求函数会重复写。此时我们再把请求数据的代码封装成一个API模块

2.封装API模块

在和src目录同级的地方,新建一个api文件夹,表示自己写的api,在里面新建一个bookAPI.js文件,这个就是封装的books的模块,关于book的所有API接口,都可以封装到这个模块。谁需要用到这个API接口,谁就导入这个模块。

bookAPI.js文件的内容:

// 导入request模块
import request from '@/utils/request.js'

// 向外按需导出一个接口函数
export const getBookListAPI = function() {
  // 记得一定要把请求到的promise对象return出去
  return request.get('/api/getbooks', {
    // 假设需要传一个参数,这里的参数是假的,演示用
    params: { id: 1 }
  })
}
<script>
// 按需导入bookAPI
import { getBookListAPI } from '@/api/bookAPI.js'

export default {
  data() {
    return {
      bookList: {}
    }
  },
  methods: {
    async getInfo() {
      // 调用getBookListAPI请求数据
      const { data: res } = await getBookListAPI()
      console.log(res)
      // 一般把请求回来的数据转存到data中
      this.bookList = res
    }
  }
}
</script>

这就实现了请求数据接口的封装,提高了代码的复用性。

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
好的,让我们开始重构axios! 首先,我们需要安装TypeScript和相关的依赖。运行以下命令: ``` npm install typescript @types/node @types/qs @types/form-data ``` 接下来,我们需要创建一个tsconfig.json文件。在项目根目录下创建一个名为tsconfig.json的文件,并将以下内容复制到其: ```json { "compilerOptions": { "lib": ["es6", "dom"], "target": "es5", "module": "commonjs", "moduleResolution": "node", "declaration": true, "sourceMap": true, "outDir": "./dist", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "exclude": ["node_modules"] } ``` 现在,我们可以开始重构axios的代码了。 首先,我们需要将axios的代码转换为TypeScript。我们可以将所有的JavaScript文件重命名为.ts文件,并使用TypeScript的语法更新代码。例如,我们可以使用类型注释来定义函数的参数类型和返回类型。 下面是一个使用TypeScript语法重构的示例: ```typescript import * as http from 'http'; import * as https from 'https'; import * as url from 'url'; import * as zlib from 'zlib'; import { Cancel, CancelToken } from './cancel'; import { isFormData } from './utils'; import settle from './core/settle'; import buildURL from './helpers/buildURL'; import parseHeaders from './helpers/parseHeaders'; import createError from './core/createError'; import enhanceError from './core/enhanceError'; import defaults from './defaults'; interface AxiosRequestConfig { url?: string; method?: string; baseURL?: string; headers?: any; params?: any; data?: any; timeout?: number; withCredentials?: boolean; responseType?: XMLHttpRequestResponseType; xsrfCookieName?: string; xsrfHeaderName?: string; onDownloadProgress?: (progressEvent: any) => void; onUploadProgress?: (progressEvent: any) => void; cancelToken?: CancelToken; } interface AxiosResponse<T = any> { data: T; status: number; statusText: string; headers: any; config: AxiosRequestConfig; request?: any; } interface AxiosError<T = any> extends Error { config: AxiosRequestConfig; code?: string; request?: any; response?: AxiosResponse<T>; isAxiosError: boolean; } interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {} interface Axios { defaults: AxiosRequestConfig; interceptors: { request: AxiosInterceptorManager<AxiosRequestConfig>; response: AxiosInterceptorManager<AxiosResponse>; }; request<T = any>(config: AxiosRequestConfig): AxiosPromise<T>; get<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; delete<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; head<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; options<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; } interface AxiosInstance extends Axios { <T = any>(config: AxiosRequestConfig): AxiosPromise<T>; <T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; } interface AxiosStatic extends AxiosInstance { create(config?: AxiosRequestConfig): AxiosInstance; CancelToken: CancelTokenStatic; Cancel: CancelStatic; isCancel: (value: any) => boolean; } interface AxiosInterceptorManager<T> { use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number; eject(id: number): void; } interface ResolvedFn<T> { (val: T): T | Promise<T>; } interface RejectedFn { (error: any): any; } interface CancelToken { promise: Promise<Cancel>; reason?: Cancel; throwIfRequested(): void; } interface Canceler { (message?: string): void; } interface CancelExecutor { (cancel: Canceler): void; } interface CancelTokenSource { token: CancelToken; cancel: Canceler; } interface CancelTokenStatic { new (executor: CancelExecutor): CancelToken; source(): CancelTokenSource; } interface Cancel { message?: string; } interface CancelStatic { new (message?: string): Cancel; } function axios<T = any>(config: AxiosRequestConfig): AxiosPromise<T> { return dispatchRequest(config); } function createInstance(config: AxiosRequestConfig): AxiosInstance { const context = new Axios(config); const instance = Axios.prototype.request.bind(context); Object.assign(instance, Axios.prototype, context); return instance as AxiosInstance; } const axiosInstance = createInstance(defaults); axiosInstance.create = function create(config) { return createInstance(Object.assign(defaults, config)); }; function getDefaultAdapter() { let adapter; if (typeof XMLHttpRequest !== 'undefined') { adapter = require('./adapters/xhr'); } else if (typeof http !== 'undefined') { adapter = require('./adapters/http'); } else if (typeof https !== 'undefined') { adapter = require('./adapters/http'); } return adapter; } function dispatchRequest<T = any>(config: AxiosRequestConfig): AxiosPromise<T> { throwIfCancellationRequested(config.cancelToken); processConfig(config); return getDefaultAdapter()(config).then((response) => { return transformResponseData(response); }, (error) => { if (error && error.response) { error.response = transformResponseData(error.response); } return Promise.reject(error); }).then((response) => { settle(resolve, reject, response); return response; }, (error) => { settle(resolve, reject, enhanceError(error)); return Promise.reject(enhanceError(error)); }); } function processConfig(config: AxiosRequestConfig): void { config.url = transformURL(config); config.headers = transformHeaders(config); config.data = transformData(config); config.params = transformParams(config); } function transformURL(config: AxiosRequestConfig): string { const { url, params, baseURL } = config; return buildURL(url!, params, baseURL); } function transformHeaders(config: AxiosRequestConfig): any { const { headers = {}, data } = config; return Object.assign(headers.common || {}, headers[config.method!] || {}, headers, data ? data.headers : null); } function transformData(config: AxiosRequestConfig): any { const { data } = config; return isFormData(data) ? data : JSON.stringify(data); } function transformParams(config: AxiosRequestConfig): any { const { params } = config; return params ? params : null; } function transformResponseData(response: AxiosResponse): AxiosResponse { response.data = transformData(response); response.headers = parseHeaders(response.headers, response.config); response.data = transformData(response); return response; } function throwIfCancellationRequested(cancelToken?: CancelToken): void { if (cancelToken) { cancelToken.throwIfRequested(); } } export default axiosInstance; ``` 现在我们已经将axios的代码转换为了TypeScript,接下来我们需要更新一下项目的结构。 我们可以将所有的TypeScript代码放在一个src目录下,并将编译后的JavaScript代码放在一个dist目录下。这样做可以使我们的代码更加结构化和易于管理。 接下来,我们需要更新package.json文件的scripts字段,以便使用TypeScript编译我们的代码。在scripts字段添加以下内容: ```json "scripts": { "build": "tsc" } ``` 现在我们可以运行npm run build命令来编译我们的代码了。 最后,我们需要更新我们的引用代码,以便使用重构后的axios。例如,我们可以使用以下代码来发送一个GET请求: ```typescript import axios from './dist/axios'; axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); ``` 这就是使用TypeScript从零重构axios的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值