背景
用过element v-loading指令的同学,相信都是对其很赞的,但有时在我们开发移动端或者选则在element之外的其他UI框架的时候,其实并没有集成v-loading这个指令,大多就一个loading图标之类的,使用的时候需要在template上面去加各种判断来显示,非常不爽。so,这必须得来实现一个v-loading指令,让代码撸起来更舒服。
实现步骤
- 创建一个loading.vue组件,包含旋转动画,和加载文字
- 创建loadingDirective
- binding.value值为true的时候,将loading组件append到目标dom上
- binding.value值为false的时候,将loading组件remove掉
上代码
文件目录
loading.vue组件
<template>
<div class="loading">
<img src="@/assets/loading.svg" class="loading-icon" alt="">
<span>加载中...</span>
</div>
</template>
<style scoped>
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loading{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba(255, 255, 255, .8);
color: #333;
}
.loading-icon{
width: 30px;
height: 30px;
animation: rotate 1s linear infinite;
}
</style>
loading.directive.ts
import Loading from "@/components/Loading.vue";
import { createApp } from "vue";
// loading组件的实例,mounted的时候保存,updated的时候使用
let loadingDom: any;
// 保存dom的初始position属性,卸载loading效果时还原
let elPosition: string;
export const loading = {
mounted(el, binding) {
init(el);
if (binding.value === true) {
addLoading(el)
} else {
removeLoading(el)
}
},
updated(el, binding) {
if (binding.value === true) {
addLoading(el)
} else {
removeLoading(el)
}
},
};
/**
* 组件挂载时初始化
*
* @param el
*/
const init = (el) => {
const app = createApp(Loading)
loadingDom = app.mount(document.createElement('div'))
elPosition = window.getComputedStyle(el).position
}
/**
* 添加loading效果
*
* @param el
*/
const addLoading = (el) => {
removeLoading(el)
el.style.position = 'relative'
el.appendChild(loadingDom.$el)
}
/**
* 取消loading效果
*
* @param el
*/
const removeLoading = (el) => {
el.style.position = elPosition || 'static'
if (el.contains(loadingDom.$el)) {
el.removeChild(loadingDom.$el)
}
}
loading指令全局引入
- /directive/index.ts
import type { App } from "vue";
import { loading } from "./loading.directive.ts";
export function setupDirective(app: App<Element>) {
app.directive("custom-loading", loading);
}
验证
- app.vue