每次接口请求完成到响应之间的时间间隔需要一个过渡动画,但是如果每次请求都去手动设置loading代码过于冗余,于是决定简单封装一个全局loading。本文的所有实例代码均为Vue3+ts编写。
这里介绍两种方法
- Pinia+antd
- 自定义插件
使用Pinia+antd
pinia安装
安装npm install pinia
在main.ts中引入
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
创建一个store文件存储和设置loading状态
import { defineStore } from "pinia";
export const useServerLoadingStore = defineStore("loading", {
state() {
return {
loading: false,
};
},
actions: {
isLoading(val: boolean) {
this.loading = val;
},
},
});
这里的loading我是用于在接口请求和响应的等待时间,在我封装的request.ts文件中定义了一个loading参数,每次请求都可以通过自定义这个loading参数来控制全局的loading效果
设置loading状态
import { useServerLoadingStore } from "../stores/serverLoading";//引入
//设置loading状态
const loading = useServerLoadingStore();
loading.isLoading(true);
接收loading状态
这里我是直接给整个页面进行了loading,使用了antd的spin组件,自定义的loading效果也是一样加一个v-if根据loading.loading的状态判断是否展示。
在上面设置loading状态为true后这里会监测到状态的改变并开始loading,直到再设置loading状态为false停止loading。
<a-spin :spinning="loading.loading" fullscreen size="large">
<router-view :key="key"></router-view>
</a-spin>
import { useServerLoadingStore } from "../stores/serverLoading";
const loading = useServerLoadingStore();
自定义插件
插件封装
<template>
<div class="loading" v-show="visible">
<div class="loader-cogs">
<span>Loading...</span>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "Loading",
setup() {
// 控制组件的状态
let visible = ref(false);
// 显示组件
let showLoading = () => {
visible.value = true;
};
// 隐藏组件
let hideLoading = () => {
visible.value = false;
};
return { visible, showLoading, hideLoading };
},
});
</script>
<style lang="scss" scoped>
.loading {
position: absolute;
inset: 0;
z-index: 9999;
margin: auto;
background-color: #7f7d7db9;
.loader-cogs {
position: absolute;
top: -20px !important;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -2;
margin: auto;
width: 100px;
height: 100px;
// position: relative;
}
}
</style>
import { App, createApp } from "vue";
import Loading from "./index.vue";
export default {
loading: null as any,
install(app: App) {
//检查是否已经存在全局的 Loading 实例。
if (this.loading) {
app.config.globalProperties.$Loading = this.loading;
return;
}
const instance = createApp(Loading);
//创建了一个新的 div 元素
const div = document.createElement("div");
//获取了当前页面的 body 元素。
const body = document.body;
body.appendChild(div);
//将之前创建的 Vue 应用程序实例 instance 挂载到之前创建的 div 元素上,并将其赋值给 loading 属性,以便在后续调用中使用。
this.loading = instance.mount(div);
//将 Loading 实例的 showLoading 和 hideLoading 方法挂载到 Vue 应用程序实例的全局属性 $Loading 上,以便在整个应用程序中方便地调用 Loading 组件的显示和隐藏方法。
app.config.globalProperties.$Loading = {
showLoading: this.loading.showLoading,
hideLoading: this.loading.hideLoading,
};
},
};
全局引入插件
import Loading from "@/components/Loading/index";
app.use(Loading);
插件使用
app.config.globalProperties.$Loading.showLoading();
app.config.globalProperties.$Loading.hideLoading();
结语
Pinia 官网:https://pinia.vuejs.org/zh/core-concepts/state.html