创建类
首先我们封装一个YcRequest类,在这个类中我们要实现get,request,delete,patch等方法。为了使我们封装的类更具有扩展性,所以我们选用创建instances的方法来实现上述的方法。
class YcRequest {
instance: AxiosInstance
interceptors?: YcRequestinterceptors
constructor(config: YcResquestConfig) {
this.instance = axios.create(config)
}
request(config: YcResquestConfig) {
}
get() {
}
delete() {
}
patch() {
我们在constror里面创建instance,使得我们没new一个类之后都能有自己的instance.传入的config用来作为create的配置
constructor(config: YcResquestConfig) {
this.instance = axios.create(config)
}
然后在到类里面实现一个request方法
request(config: YcResquestConfig) {
this.instance.request(config).then((res) => {
console.log(res);
})
}
然后再到出口文件里new一个实例,同时传入基础config (baseURL,timeout)。
const ycrequest = new YcRequest({
baseURL: BASE_URL,
timeout: TIME_OUT,
})
再到main.js里应用一下,同时传入config(url和method)。(注意:传入的这些config配置会以一个优先顺序进行合并。这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者)
YcRequest.request({
url: '/home/multidata',
method: 'GET',
})
拦截器
接下来在我们封装的网络请求类中封装我们的拦截器。首先拦截器只会在请求的实例有,并不会出现在config里。例如一下两种方式
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
为了使我们封装的类更具有扩展性,避免创建出来的实例都能有自己选择性的拦截器,所以我们要做的事就是把interceptors扩展到config里面去。怎么样扩展呢?无非就是在config类的基础上再继承一个拦截器的接口。
interface YcResquestConfig extends AxiosRequestConfig {
interceptors?: YcRequestinterceptors
}
interface YcRequestinterceptors {
requestInterceptor?: (value: AxiosRequestConfig) => AxiosRequestConfig
requestInterceptorCatch?: (error: any) => any
responseInterceptor?: (value: AxiosResponse) => AxiosResponse
responseInterceptorCatch?: (error: any) => any
}
config原本的类是AxiosRequestConfig。但是我们可以通过让我们封装的接口YcResquestConfig继承接口AxiosRequestConfig
。我们在自己封装的接口YcResquestConfig中实现了interceptors属性,而这个属性又满足YcRequestinterceptors接口,在那个接口中有拦截器的请求和响应方法,当然这些都是可选的。所以我们通过这种方式来实现了对config属性的扩展,添加了拦截器。
interceptors?: YcRequestinterceptors
constructor(config: YcResquestConfig) {
this.instance = axios.create(config)
this.interceptors = config?.interceptors
//实例的拦截器
this.instance.interceptors.request.use(this.interceptors?.requestInterceptor,this.interceptors?.requestInterceptorCatch)
this.instance.interceptors.response.use(this.interceptors?.responseInterceptor, this.interceptors?.responseInterceptorCatch)
}
最后我们在constructor中来实现拦截器。先可以把拦截器保存一下放到里面,然后再来现实拦截器方法。
const ycrequest = new YcRequest({
baseURL: BASE_URL,
timeout: TIME_OUT,
interceptors: {
requestInterceptor: (config) => {
console.log("请求拦截");
return config
},
requestInterceptorCatch: (err) => {
return err
},
responseInterceptor: (config) => {
console.log("响应拦截");
return config
},
responseInterceptorCatch: (err) => {
return err
}
}
})
这样我们在用的时候就可以把拦截器当成config传给YcRequest类,这样我们就完成了对于实例的拦截器封装,实例下所有的请求都会带上这些拦截器。
每一个请求的拦截器封装
如果说我们个别的请求不满足于实例封装的拦截器,那我们还可以扩展。例如将传给request的config也从AxiosRequestConfig改为YcResquestConfig。这样我们也可以在传给requestconfig的时候传入拦截器 request(config: YcResquestConfig) { if(config.interceptors?.requestInterceptor) { console.log(config); config = config.interceptors.requestInterceptor(config) console.log(config); } this.instance.request(config).then((res) => { if (config.interceptors?.responseInterceptor) { res = config.interceptors?.responseInterceptor(res) } console.log(res); }) }
request(config: YcResquestConfig) {
if(config.interceptors?.requestInterceptor) {
console.log(config);
config = config.interceptors.requestInterceptor(config)
console.log(config);
}
this.instance.request(config).then((res) => {
if (config.interceptors?.responseInterceptor) {
res = config.interceptors?.responseInterceptor(res)
}
console.log(res);
})
}
首先我们要判断一下传过来的config里面有没有requestInterceptor拦截器。如过有,我们就先把config传给那个requestInterceptor拦截器,做一些操作,做完之后再把config返回。把返回的config传给request,同理再处理responseInterceptor
YcRequest.request({
url: '/home/multidata',
method: 'GET',
interceptors: {
requestInterceptor: (config) => {return config},
responseInterceptor: (res) => {return res}
}
})
在main.js中就是这么使用。
补充一点
如果我们想在创建出来的所有YcRequest实例中都有的拦截器的话,就在constructor中补上一段全局的拦截器
his.instance.interceptors.request.use(config => {
return config
},err => {
return err
})
this.instance.interceptors.response.use(config => {
return config
}, err => {
return err
})
使用elementui里的loading组件的显示和隐藏
我们调用element组件的一个loading加载组件。
import { ElLoading } from 'element-plus'
通过在全局拦截器里调用ElLoading里的services方法同时传入options,这样就能实现loading的效果
this.instance.interceptors.request.use(config => {
console.log(config);
this.loadingInstance = ElLoading.service({
text: '加载中。。。。。',
background: 'rgba(0,0,0,0.5)'
})
return config
},err => {
return err
})
然后在全局响应拦截器里调用close方法来关闭loading
this.instance.interceptors.response.use(config => {
setTimeout(() => {
this.loadingInstance?.close()
}, 2000);
return config
}, err => {
return err
})
考虑到有一些请求是不需要loading效果的,所以我们要设计在传给request的时候传入一个参数showloading,如下:
YcRequest.request({
url: '/home/multidata',
method: 'GET',
showloading: true
})
要在config里加上一个参数,我们要在YcResquestConfig接口上扩展
interface YcResquestConfig extends AxiosRequestConfig {
interceptors?: YcRequestinterceptors
showloading?: Boolean
}
然后在YcRequest类中加上showloading属性。接着在constructor里给showloading赋值,默认为true
this.showloading = config.showloading ?? true
接着在发送请求的时候就可以加上一个判断,如果 showloading的值还是true的话就显示loading效果,否则不显示
if (this.showloading === true ) {
this.loadingInstance = ElLoading.service({
text: '加载中。。。。。',
background: 'rgba(0,0,0,0.5)'
})
}
最后一步就是让request里的showloading能控制类里的showloading值。拿到request里的config的showloading值,判断如果是等于false就把类里的showloading的值改为false。这样就完成了通过请求内部的showloading值取消loading动画
if(config.showloading === false) {
this.showloading = false
}
注意:修改完showloading之后,在下一个请求中showloading默认还是false,所以我们要在一个请求完之后修改showloading的值为true
总结:
1 为什么要用类封装而不是函数封装?
类的可扩展性强,封装性强,可以把很多函数封装到类里,继承什么的都会好很多
2 为什么可以自己扩展接口
不满足于给定的接口 我们可以设计一个自己的接口,这个接口可以继承原先给定的接口,同时又可以满足我们给定的东西例如这个拦截器/