前言
在現代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的不斷發展和完善,我們期待有更多創新的方法來優化用戶界面的交互效果。