为什么要设置全局loading?
在项目开发过程中,请求接口的时候延迟没有数据,页面感觉狠卡顿,这个时候就要用loading来做一个延迟界面。
但是每个界面都写loading的话就会很复杂,所以今天给大家带来了一个全局loading的文章,比较适合新手,要具备vuex的基础知识和vue中setup的使用,如果之前没有涉及的话,这边建议去看官网,网上的资料鱼龙混杂。vue的官网写的很好。
每个人都有每个人的全局loading写法。
实现效果
QQ录屏20230613102417
实现思路
loading界面书写:
loading.vue
<template>
<div class="flex-content">
<div class="flex-center">
<div class="loading cube-box">
<div class="outer-box">
<div class="large-box">
<div class="small-box"></div>
</div>
</div>
</div>
<div class="text">Loading...</div>
</div>
</div>
</template>
<style src="@/assets/css/utils/loading.css" scoped>
</style>
loading.css
* {
margin: 0;
box-sizing: border-box;
}
.flex-content {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.flex-center:hover {
transition: transform 0.2s ease;
border: 1px solid #eee;
transform: scale(1.1);
cursor: pointer;
}
.loading{
display: flex;
justify-content: center;
align-items: center;
}
.outer-box {
width: 3em;
height: 3em;
animation: cube-box-ani 1s infinite ease-in-out;
outline: 1px solid transparent;
}
.large-box {
height: 3em;
width: 3em;
background-color: RGB(42,194,209);
outline: 1px solid transparent;
}
.small-box {
height: 3em;
width: 3em;
background-color: white;
z-index: 1;
outline: 1px solid transparent;
animation: small-box-ani 1s alternate infinite ease-in-out;
}
@keyframes small-box-ani {
0% {
transform: scale(0.2);
}
100% {
transform: scale(0.75);
}
}
@keyframes cube-box-ani {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(90deg);
}
}
.text{
color: RGB(130,130,130);
margin-top: 20px;
}
store设置loading:
loading.js
export default{
state: {
loading: false
},
getters: {
},
mutations: {
setLoading(state,flag){
state.loading = flag
}
},
actions: {
},
modules: {
}
}
store/index.js (这里配置了让vuex数据持久化vuex-persistedstate)
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import loading from './modules/loading'
const store = createStore({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
loading,
},
/* vuex数据持久化配置 */
plugins: [
createPersistedState({
// 存储方式:localStorage、sessionStorage、cookies
storage: window.sessionStorage,
// 存储的 key 的key值
key: "store",
reducer(state) { //render错误修改
// 要存储的数据:本项目采用es6扩展运算符的方式存储了state中所有的数据
return { ...state };
}
})
]
})
export default store;
设置全局loading.js
loading.js
// 全局loading设置
import store from '@/store'
let loadingNum = 0;
// 开始显示Loading
const startLoading = () => {
loadingNum++;
store.commit("setLoading", true);
};
// 关闭Loading
const endLoading = () => {
loadingNum--;
loadingNum = loadingNum < 0 ? 0 : loadingNum;
if (!loadingNum) {
store.commit("setLoading", false);
}
};
// 重置函数
const resetLoading = () => {
loadingNum = 0;
console.log(store, "store");
store.commit("setLoading", false);
};
// 导出
export default {
startLoading,
endLoading,
resetLoading,
};
拦截器配置
请求拦截器 request.js
import axios from "axios";
import loading from "@/assets/js/utils/loading";
//1.利用axios对象的方法create,去创建一个axios实例。
const requests = axios.create({
//配置对象
//接口当中:路径都带有/api 基础路径,发送请求的时候,路径当中会出现api
baseURL: "http://127.0.0.1:8080/",
//代表请求超时的时间
timeout: 5000,
});
//请求拦截器:
requests.interceptors.request.use((config) => {
//解析和上传到后端的时候进行loading加载显示
loading.startLoading();
return config;
}),
(error) => {
//关闭loading
loading.endLoading();
return Promise.reject(error);
};
//响应拦截器
requests.interceptors.response.use(
(res) => {
loading.startLoading();
return res;
},
(error) => {
loading.endLoading();
return;
}
);
//对外暴露
export default requests;
路由拦截器
import { createRouter, createWebHistory } from "vue-router";
import loading from "@/assets/js/utils/loading";
const routes = [
{
path: '/',
name: 'main',
component: () => import("../views/Main.vue")
},
{
path: "/test",
name: "test",
component: () => import("../views/Test.vue"),
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
router.beforeEach((to, from, next) => {
// 重置 全局loading
loading.resetLoading();
next();
});
export default router;
全局loading要设置在App.vue界面。这样才能做到设置全局loading。
App.vue
<template>
<div id="app">
<router-view v-if="loadingState" />
<loading v-if="!loadingState" />
</div>
</template>
<script setup>
import loading from "@/components/utils/loading.vue";
import { computed } from "vue";
import { useStore } from "vuex";
const store = useStore();
const loadingState = computed(() => store.state.loading.loading);
</script>
<style>
* {
padding: 0;
margin: 0;
}
html,
body,
#app {
width: 100%;
height: 100%;
}
</style>