1、首先肯定要写出一个loading加载动画了
waiting.vue文件
<template><div class="waiting_div"><div class="background_div"><!-- iconfont icon-jiazaidonghua 为我自己的字体图标,可自行替换,不想替换就用下面的加载文字 --><span class="iconfont icon-jiazaidonghua"></span><!-- <span class="iconfont">加载---</span> --></div></div>
</template>
<script setup>
</script><style scoped lang="less">.waiting_div {//注意了,我把它隐藏了!!!!!!!!!!!!visibility: hidden;position: fixed;.background_div {background-color: #fff;opacity: 0.8;width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;.iconfont {font-size: 50px;color: #297aff;animation: icon_rotate 1.5s ease-in-out infinite alternate-reverse;}}}@keyframes icon_rotate {0% {transform: rotate(0deg);}100% {transform: rotate(480deg);}}
</style>
2、注册自定义指令v-waiting
v_directive.js文件
// 注册vue自定义指令工具/*** el 绑定元素dom* val 绑定的值* vnode */
let _ = {}
//设置waiting元素的样式,根据目标taregt样式进行设置
const set_waiting_style = (waiting_dom, target = {}) => {const bound = target.getBoundingClientRect()const { height, left, width, top } = boundwaiting_dom.setAttribute('style', `width:${width}px;height: ${height}px;left:${left}px;top:${top}px;visibility:visible;`)
}
//清除waiting元素的样式,让其继续保持隐藏
const clear_waiting_style = (waiting_dom) => {if (waiting_dom) {waiting_dom.setAttribute('style', `visibility:hidden;`)}
}
// 自定义等待loading v-waiting指令
//我个人是不推荐页面同时有多个loading的
const waiting = (Vue) => {Vue.directive('waiting', (el, val, vnode) => {if (val.value) {if (!_.waiting_dom) {const waiting_dom = document.querySelector(".waiting_div")_.waiting_dom = waiting_dom}set_waiting_style(_.waiting_dom, el)} else {clear_waiting_style(_.waiting_dom)return}})
}const v_directive = (Vue) => {waiting(Vue)
}export {v_directive
}
3、使用
main.js挂载自定义指令
import { createApp} from 'vue'
import App from './App.vue'
//...
//@utils/vue_instruct,是我自己的文件路径,@utils是我配置的快捷地址
import { v_directive } from '@utils/vue_instruct'//...
const app = createApp(App)
app.use(router).use(v_directive).mount('#app')
app.vue使用loading组件
<template><div class="contain" v-waiting="loading"><!-- 在app.vue任意位置引入一次即可 --><waiting /></div>
</template>
<script setup>import waiting from "@/components/card/waiting.vue";import { onMounted, ref } from "vue";onMounted(() => {setTimeout(() => {loading.value = false}, 2000);});const loading = ref(true);
</script><style scoped lang='less'>.contain{height:600px}
</style>
效果截图:
4、问题:
不能同时存在多个loading:我个人的建议是一个页面尽量确保只有一个loading正在运行(并非只能写一个v-waiting,而是确保只有一个v-waiting正在运行),多个loading动画同时运行时。
如果非要同时运行多个loading,解决方案:
无需在app.vue中引入waiting 组件,而是在v_directive.js引入waiting组件,并且在绑定的loading值为false时移除waiting组件,在值为true时,向body或者某个元素上插入waiting组件
页面多个loading改为一个loading,解决方案:
有多个loading,无非是因为我们调取了多个接口,不想再接口数据未返回的时候让用户进行操作,建议用Promise.all进行解决。拿到所有接口成功的回调,再loading=false