问题
在实际项目中,前端发送请求获取数据刷新页面是大家非常熟悉的操作。请求响应的快慢,与业务逻辑的复杂程度和网络环境有关,很有可能出现请求延迟的情况,如果我们不处理请求响应前后的交互,那么页面在请求响应成功之前这段事件就没有任何提示信息,这是非常影响用户体验的。但是如何为每个请求单独处理loading
状态,那么工作量是非常大的。
axios
是我们开发中常用的请求工具库,并且和vue能很好的搭配。下面向大家介绍我自己在项目中使用axios
配置来完场全局的loading
状态处理
store状态记录
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
// 是否在请求中
isAppending: false
},
mutations: {
changeAppending(state, bool) {
state.isAppending = bool;
}
}
});
axios 配置
axios/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67/**
* axios配置
*/
import axios from "axios";
import qs from "qs";
// 引入 vuex 入口文件 记录全局loading状态
import store from "../store/store";
// 定时器数组,一般我们都是等请求时间超过1秒后,才出现loading状态,如果一开始就提示,用户体验也不是很好
let timers = [],
timer = null;
const service = axios.create({
// 设置超时时间
timeout: 60000,
baseURL: process.env.VUE_APP_BASE_URL
});
/*
* post请求的时候,我们需要加上一个请求头,所以可以在这里进行一个默认的设置
*即设置post的请求头为application/x-www-form-urlencoded;charset=UTF-8
*/
service.defaults.headers.post["Content-Type"] =
"application/x-www-form-urlencoded;charset=UTF-8";
// 拦截请求
service.interceptors.request.use(
config => {
// 配置formData的方式
config.data = qs.stringify(config.data);
// 每次请求开始前 都开启延迟定时器,并记录在数组中,便于响应回来后 清除
timer = setTimeout(() => {
!store.state.isAppending && store.commit("changeAppending", true);
}, 1000);
timers.push(timer);
return config;
},
error => {
// ...
return Promise.reject(error);
}
);
// 拦截响应
service.interceptors.response.use(
response => {
// 请除所有的定时器;
clearAllTimer();
// 去除 loading 效果
store.commit("changeAppending", false);
return response;
},
error => {
clearAllTimer();
store.commit("changeAppending", false);
return Promise.reject(error);
}
);
function clearAllTimer() {
timers.forEach(item => {
clearTimeout(item);
});
timers = [];
}
export default service;
vue项目中使用
我的项目中应用了vue的UI组件库—-vant
,使用其提供的Toast
组件即可完成loading状态的交互。
具体使用main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import Vue from "vue";
// 按需引入Toast
import { Toast } from "vant";
import App from "./App.vue";
import router from "./router/index";
import axios from "./axios/index";
import store from "./store/store";
import "./common/less/reset.less";
// 注册
Vue.use(Toast);
Vue.config.productionTip = false;
Vue.prototype.$axios = axios;
// runtimex
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
最后,我们在项目根组件App.vue
中监听 isAppending
状态即可app.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37<template>
<div id="app">
<router-view />
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "App",
data() {
return {};
},
computed: {
...mapState(["isAppending"])
},
watch: {
isAppending(val) {
console.log("isApending", val);
val
? this.$toast.loading({
message: "加载中...",
duration: 0,
forbidClick: true
})
: this.$toast.clear();
}
},
created() {},
methods: {}
};
</script>
<style lang="less">
@import "./common/less/reset.less";
</style>
大功告成了!