实现了 全屏loading hooks 和 元素内部loading
1.准备loading组件 loading.vue
<template>
<transition name="fade">
<div v-if="visible">
<div class="loading-mask" :style="getStyle">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none"/>
</svg>
<span style="color: #409eff;font-size: 14px;margin-top: 4px">loading...</span>
</div>
</div>
</transition>
</template>
<script>
import { ref, computed } from 'vue'
export default {
name:'Loading',
setup(props, { emit }) {
let visible = ref(false)
const isFixed = ref(true)
const getStyle = computed(() => {
return isFixed.value ? 'position: fixed' : 'position: absolute'
})
return {
visible,
show: () => visible.value = true,
close: () => visible.value = false,
changeFix: (v) => isFixed.value = v,
getStyle,
isFixed
}
},
}
</script>
<style lang="scss">
.fade-enter-active, .fade-leave-active {
transition: all .5s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
scale: 0;
}
.fade-enter-to, .fade-leave-from {
opacity: 1;
scale: 1;
}
.loading-mask {
z-index: 2000;
background-color: rgba(33,33,33,.4);
margin: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: opacity .3s;
.circular {
height: 42px;
width: 42px;
animation: loading-rotate 2s linear infinite;
}
.path {
animation: loading-dash 1.5s ease-in-out infinite;
stroke-dasharray: 90,150;
stroke-dashoffset: 0;
stroke-width: 2;
stroke: #409eff;
stroke-linecap: round;
}
}
@keyframes loading-rotate{to{transform:rotate(1turn)}}
@keyframes loading-dash {
0% {
stroke-dasharray: 1,200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90,150;
stroke-dashoffset: -40px;
}
100% {
stroke-dasharray: 90,150;
stroke-dashoffset: -120px;
}
}
</style>
2.实现全屏hooks (其实就是absolute,并且装载到body里)
useLoading.ts
import Loading from "../components/Loading.vue"
import {createVNode, render} from "vue";
export default function useLoading() {
let element;
const oldEle = document.getElementById("#loading-zzz")
if(oldEle) {
element = oldEle;
} else {
element = document.createElement("div");
element.setAttribute("id", "#loading-zzz")
document.body.appendChild(element);
}
element.setAttribute("time", new Date().getTime() + '')
const Vloading = createVNode(Loading, {});
render(Vloading, element);
let instance = Vloading.component.ctx;
return {
show() {
instance.show();
},
close() {
instance && instance.close()
}
}
}
使用
import useLoading from "../hooks/useLoading";
const {show, close} = useLoading()
function handleShow() {
show()
// close
//setTimeout(close, 3000)
}
2.定义指令 loading.ts
import {App, createVNode, render} from "vue";
import Loading from '../components/Loading.vue'
export default function(app: App<Element>) {
app.directive("loading", {
mounted(el, binding) {
el.style.position = 'relative'
const Vloading = createVNode(Loading, {})
render(Vloading, el)
el.instance = Vloading.component.ctx
el.instance.changeFix(false)
console.log(el.instance)
!!binding.value && el.instance.show()
},
updated(el, binding) {
const instance = el.instance
if(binding.oldValue !== binding.value) {
!!binding.value ? el.instance.show() : el.instance.close()
}
}
})
}
使用(记得注册)我采用的 app.use
<div v-loading="loading"
style="width: 300px;height: 300px;background-color: #ff1212"></div>