前言
在现代Web开发中,提升用户体验一直是开发者们追求的目标之一。其中,一个常见的场景就是在用户与应用程序进行交互时,特别是当进行异步操作时(如网络请求),为用户提供即时的反馈,避免用户因为等待而感到困惑或不满。这通常通过显示一个加载指示器(通常称为Loading效果)来实现。本文将深入探讨如何在Vue 3中通过自定义指令的方式来实现Loading加载效果。自定义指令是Vue提供的一种强大工具,允许我们在Vue模板中附加自定义行为。通过自定义指令,我们可以轻松地创建可复用的、可配置的加载效果组件,并将其应用于任何需要显示加载状态的元素上。
演示效果图
新建index.vue文件
在components
目录下新建loading
目录,并在loading
目录下新建index.vue
文件
<template><div class="loading-container" v-if="show"><div class="loader"></div><div class="tips">正在快马加鞭的加载中....</div></div>
</template><script setup name="Loading">
const show = ref(false);const showLoading = () => {show.value = true;document.body.style.overflow = "hidden";document.addEventListener("touchmove", () => {}, true);
};
const hideLoading = () => {show.value = false;var mo = function (e) {e.preventDefault();};document.body.style.overflow = "";document.removeEventListener("touchmove", mo, true);
};onMounted(() => {});defineExpose({show,showLoading,hideLoading,
});
</script><style scoped>
.loading-container {position: fixed;top: 0;left: 0;right: 0;bottom: 0;z-index: 9999;background-color: rgba(255, 255, 255, .9);
}
.tips {font-family: "Open Sans";color: #52b852;font-size: 1rem;width: 100%;text-align: center;position: absolute;top: 55%;line-height: 30px;
}
.loader {width: 40px;aspect-ratio: 0.577;clip-path: polygon(0 0, 100% 100%, 0 100%, 100% 0);position: relative;animation: l19 2s infinite linear;overflow: hidden;position: relative;left: 50%;top: 45%;margin: 0 0 0 -25px;
}
.loader:before {content: "";position: absolute;inset: -150% -150%;background: repeating-conic-gradient(from 30deg,#ffabab 0 60deg,#abe4ff 0 120deg,#ff7373 0 180deg);animation: inherit;animation-direction: reverse;
}
@keyframes l19 {100% {transform: rotate(360deg);}
}
</style>
新建loading.js文件
在index.vue
的同级目录中新建loading.js
文件来创建自定义指令
import {createVNode, render, cloneVNode} from "vue"
import Loading from "./index.vue"export default {install(app) {// 使用vue底层的createVNode方法将组件渲染为虚拟节点const VNode = createVNode(Loading)// 使用render函数将组件挂载到body中render(VNode, document.body)// 定义全局方法设置组件的显示和隐藏app.config.globalProperties.$showLoading = VNode.component?.exposed.showLoadingapp.config.globalProperties.$hideLoading = VNode.component?.exposed.hideLoadingconst weakMap = new WeakMap()// 自定义Loading指令app.directive("sy-loading", {mounted(el) {if (weakMap.get(el)) return// 记录当前绑定元素的positionweakMap.set(el, window.getComputedStyle(el).position)},updated(el, binding) {const oldPosition = weakMap.get(el);// 如果不是position: relative或者absolute,就设置为relative// 这里的目的是确保loading组件正确覆盖当前绑定的元素if (oldPosition !== 'absolute' && oldPosition !== 'relative') {el.style.position = 'relative'}// 克隆一份loading元素,// 作用是当页面上有多个zx-loading时,每个dom都维护一份属于自己的loading,不会冲突const newVNode = cloneVNode(VNode)// 挂载当前节点render(newVNode, el)// 判断绑定的值if (binding.value) {newVNode.component?.exposed.showLoading()} else {newVNode.component?.exposed.hideLoading(() => {// 还原布局方式el.style.position = oldPosition})}}})}
}
1. loading.ts
TS写法。上面是js写法,选其中一种即可
import type {App, VNode,} from "vue"
import {createVNode, render, cloneVNode} from "vue"
import Loading from "./index.vue"export default {install(app: App) {// 使用vue底层的createVNode方法将组件渲染为虚拟节点const VNode: VNode = createVNode(Loading )// 使用render函数将组件挂载到body中render(VNode, document.body)// 定义全局方法设置组件的显示和隐藏app.config.globalProperties.$showLoading = VNode.component?.exposed.showLoadingapp.config.globalProperties.$hideLoading = VNode.component?.exposed.hideLoadingconst weakMap = new WeakMap()// 自定义Loading指令app.directive("sy-loading", {mounted(el) {if (weakMap.get(el)) return// 记录当前绑定元素的positionweakMap.set(el, window.getComputedStyle(el).position)},updated(el: HTMLElement, binding: { value: Boolean }) {const oldPosition = weakMap.get(el);// 如果不是position: relative或者absolute,就设置为relative// 这里的目的是确保loading组件正确覆盖当前绑定的元素if (oldPosition !== 'absolute' && oldPosition !== 'relative') {el.style.position = 'relative'}// 克隆一份loading元素,// 作用是当页面上有多个zx-loading时,每个dom都维护一份属于自己的loading,不会冲突const newVNode = cloneVNode(VNode)// 挂载当前节点render(newVNode, el)// 判断绑定的值if (binding.value) {newVNode.component?.exposed.showLoading()} else {newVNode.component?.exposed.hideLoading(() => {// 还原布局方式el.style.position = oldPosition})}}})}
}
main.js引入
在main.js
中引入loading.js文件。
import Loading from '@/components/loading/Loading.js'
app.use(Loading)
在组件中使用
v-sy-loading="fullscreenLoading"
在任意组件中的任意标签元素中添加v-sy-loading指定,并设置一个boolean值的参数,即可控制页面的loading加载效果
End
通过本文的介绍,我们详细探讨了如何在Vue 3中利用自定义指令来实现灵活且可复用的Loading加载效果。这一功能不仅优化了用户与应用程序之间的交互体验,还使得加载状态的显示更加直观和易于管理。我们介绍了自定义指令的基本概念、创建过程以及如何在Vue模板中优雅地应用该指令。希望这些内容能帮助你在Vue 3项目中更好地实现Loading加载效果,提升用户体验。未来,随着Vue.js的不断发展和完善,我们期待有更多创新的方法来优化用户界面的交互效果。