##在我们日常开发中,axios请求是必不可少的,甚至连vue作者尤雨溪都放弃了对vue-resource的维护,推荐我们使用axios库来进行前后端交互,而在开发过程中在每个单页面引入axios显然是比较麻烦的,一些功能实现起来也比较麻烦,比如说发出请求后显示一个遮罩,在请求成功后遮罩消失这一功能的实现,在axios请求统一管理之前,虽然在每个axios事件发送前后设置遮罩显示或隐藏状态是完全行得通的,但是相对来说比较繁琐,当我们请求比较多时,就会比较麻烦,因此今天分享一个本人刚实现的一个统一遮罩处理的方法。使用到的工具有 vant+vuex+axios。
这里我是用的是vant组件库中的两个组件OverLay以及loading组件结合使用的
<template>
<div>
<van-overlay :show="show">
<div class="wrapper" @click.stop>
<van-loading type="spinner" />//这里是加载中图标
</div>
</van-overlay>
</div>
</template>
<script>
export default {
data(){
return{
show:this.show1
}
},
props:["show1"],//通过父组件传过来的show1进行遮罩显示与隐藏 show1为布尔值
watch:{
"show1":function(n){
this.show=n
}
},
methods:{
}
};
</script>
<style scoped>
.wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
</style>
之后将这个组件导入到app.vue中进行备用
要实现这个功能,第一步也是最关键的一步就是对axios进行一个封装。我现在与src文件夹平级的位置创建一个request文件夹,内部包含两个js文件 分别是http.js(该文件的主要作用是创建一个axios实例,进行相关配置,将axios实例放在一个方法中抛出)。以及api.js(这部分功能是获取axios实例,将所有的接口路径写在这个文件中,抛出后在需要的页面进行引入。)
1.http.js
首先必须对axios进行安装
npm install axios
安装好后再http.js中进行导入
const axios = require("axios")
//这部分是为了判断当前环境是生产环境还是开发环境,因为设置了跨域代理,代理名是/api所以当是开发模式的时候,我这里将baseUrl设置为"/api",开发模式则获取当前环境的域名。
let baseUrl;
if(process.env.NODE_ENV==="development"){
baseUrl = "/api"
}else{
baseUrl = window.location.origin
}
接下来我们就通过axios.create()创建一个axios实例。
//这里的instance 我们可以把他直接理解为我们单页面引入的axios,不过这里我们可以自己配置一些东西 比如说baseUrl,responseType,
let instance = axios.create({
baseURL: baseUrl,//会自动添加到我们请求的路径前面
timeout: 0,//延时时间
responseType: 'json'//规定响应内容默认的格式为json格式
})
接下来我们创建一个http()方法,通过http方法将我们创建好的instance结合promise来实现我们封装好的axios代码如下
function http(options, flag) {
return new Promise((resolve, reject) => {
resolve(instance(options))
})
}
export default http //将http方法抛出
到这里,最最简单的一个axios的封装就完成了,当然还有一些需要完善的地方,我们下一步要做的就是通过拦截器来对现在的步骤进行完善。
拦截器分为两种,分别是请求拦截器和响应拦截器,对应的也分别是我们发送请求之前以及获取到响应之前这两个阶段。(拦截器具体用处可移步axios文档)
首先我们要对响应拦截器进行处理,废话不多说,先贴代码
instance.interceptors.response.use(
res => {
return res;
},
err => {
return Promise.reject(err)
}
)
拦截器包含两个参数分别对应成功和失败时的信息,此外必须通过return将对应的信息进行返回,否则我们的请求会卡在这个地方,无法继续。
接下来考虑到我们的遮罩是全局任何页面都要适用,所以我是用vuex将需要传的值存储再state中,再与App.vue中的父子传值这里进行结合。
<template>
<div id="app">
<router-view/>
<OverLay :show1="$store.state.show"></OverLay>//这里关键
//vuex是响应式的
</div>
</template>
<script>
import OverLay from "@/components/OverLay.vue"
export default {
data(){
return{
show:true
}
},
components:{
OverLay
}
}
</script>
<style lang="scss">
</style>
vuex中的代码比较简单
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
show:false,
times:0 //判断当前同时共有多少个请求 所有请求结束后(即值为0)遮罩消失
},
mutations: {
increment (state,n) {
// 变更状态 n为布尔值
state.show=n
},
addTimes(state){
state.times++
//该步骤放在响应发出之前
},
reduceTimes(state){
state.times--
//该步骤放在响应结束之后
}
},
actions: {
},
modules: {
}
})
此时再贴出http.js相关代码
import store from "../store/index.js" //引入store
function http(options, flag) {
return new Promise((resolve, reject) => {
instance.interceptors.request.use(res => {
times++
//请求前拦截 每次++ 判断当前共有多少次请求
//并开启遮罩
store.commit("increment", true)
return res
}, err => {
return Promise.reject(err)
})
instance.interceptors.response.use(res => {
//获取到响应前拦截 每次-- 当times为0时说明当前接口全部请求完毕
//关闭遮罩 即 store.commit("increment", false) 为false
times--;
console.log(times)
if (times == 0) {
store.commit("increment", false)
}
return res;
},
err => {
times--;
if (times == 0) {
store.commit("increment", false)
}
return Promise.reject(err)
}
)
resolve(instance(options))
})
}
至此我们全局遮罩已经实现
接下来再回到我们统一管理接口的文件api.js中
import http from "./http.js"
// import qs from "qs"
const getCountry = () => {
return http({
url: "/product/queryFromTrans.html",
method: "post",
params: { codeType: 'idtype' }
})
}
const getProvince = () => {
return http({
method: "post",
url: "/edor/initCities.html"
})
}
//获取银行列表
const getEdorBank = () => {
return http({
method: 'post',
url: '/product/getEdorBank.html',
})
}
export {
getCountry,getProvince,getEdorBank
}//这种导出方法引用时必须使用解构复制
实例引用
import { getCountry} from "@request";//这里路径为自定义的 可以自行设置
在下萌新一枚,有不足之处欢迎各位留言指出