vue3自定义loading加载动画指令

 //vLoading.ts

import { ref, watch } from 'vue'; 
 
let  divEle:any = null

// 创建一个 ref 用于管理加载状态 
export const vloadingShow = ref(false); 
 
export const vLoading = { 
  mounted(el: any, binding: any) { 
    // 
    const loadingDiv: any = document.createElement('div');  
    loadingDiv.classList.add('Svloading');  
    loadingDiv.style.position  = 'fixed'; 
    loadingDiv.style.top  = '0'; 
    loadingDiv.style.left  = '0'; 
    loadingDiv.style.width  = '100%'; 
    loadingDiv.style.height  = '100%'; 
    loadingDiv.style.backgroundColor  = 'rgba(0, 0, 0, 0.2)'; 
    loadingDiv.style.display  = 'flex';   
    loadingDiv.style.justifyContent  = 'center'; 
    loadingDiv.style.alignItems  = 'center'; 
    loadingDiv.style.zIndex  = 9999; 
    loadingDiv.style.userSelect  = 'none';  
    loadingDiv.style.webkitUserSelect  = 'none';  
    loadingDiv.style.msUserSelect  = 'none';  

    // 关闭的按钮
    const closeButton:any = document.createElement('div');  
    closeButton.textContent  = '关闭'; 
    closeButton.style.position  = 'absolute'; 
    closeButton.style.top  = '10px'; 
    closeButton.style.right  = '10px'; 
    closeButton.style.backgroundColor  = 'transparent'; 
    closeButton.style.color  = 'white'; 
    closeButton.style.border  = 'none'; 
    closeButton.style.fontSize  = '20px'; 
    closeButton.style.cursor  = 'pointer'; 


    closeButton.addEventListener('click',  () => { 
      vloadingShow.value  = false; 
    }); 
 
    const img = document.createElement('img');  
    img.src  = '/svLogo.gif';  
    img.alt  = '加载中。。。'; 
    img.style.width  = '100px'; 
 

    loadingDiv.appendChild(img);  
    loadingDiv.appendChild(closeButton);  

    


    el.loadingDiv  = loadingDiv;

    divEle = loadingDiv
    if (vloadingShow.value)  { 
      document.body.appendChild(loadingDiv);  
    } 
  }, 
  unmounted(el: any) { 
    // 组件销毁时,移除 Svloading 元素 
    const loadingDiv = el.loadingDiv;  
    if (loadingDiv) { 
      const parent = loadingDiv.parentNode;  
      if (parent) { 
        parent.removeChild(loadingDiv);  
      } 
    } 
  }, 
}; 

watch(() => vloadingShow.value,  (newVal) => { 
  if (newVal && divEle) { 
    document.body.appendChild(divEle);  
  } else { 
    // 如果需要隐藏加载,移除所有加载元素 
    const loadingElements = document.querySelectorAll('.Svloading');  
    loadingElements.forEach((element)  => { 
      const parent = element.parentNode;  
      if (parent) { 
        parent.removeChild(element);  
      } 
    }); 
  } 
}); 
 

//main.ts

import { vLoading } from '@/utils/directive/vLoading'; 


const app = createApp(App);

// 注册指令
app.directive('Svloading',  vLoading);

app.mount('#app')

使用


### Vue3 中实现自定义 `loading` 指令Vue3 中,可以通过自定义指令来增强组件的功能。以下是关于如何创建和使用一个名为 `v-loading` 的自定义指令的具体方法。 #### 创建自定义指令 通过调用 Vue 应用实例上的 `app.directive()` 方法可以注册全局指令。下面是一个完整的例子: ```javascript // 导入 Vue 和其他必要的库 import { createApp } from &#39;vue&#39;; const app = createApp({}); // 注册全局自定义指令 v-loading app.directive(&#39;loading&#39;, { beforeMount(el, binding) { const isLoading = Boolean(binding.value); // 获取绑定的值 (true/false) if (isLoading) { el.style.position = &#39;relative&#39;; // 设置相对定位以便叠加遮罩层 const overlay = document.createElement(&#39;div&#39;); overlay.className = &#39;overlay&#39;; overlay.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.8); z-index: 9999; display: flex; justify-content: center; align-items: center; `; const spinner = document.createElement(&#39;span&#39;); // 加载动画图标 spinner.textContent = &#39;加载...&#39;; spinner.style.color = &#39;#4caf50&#39;; spinner.style.fontSize = &#39;16px&#39;; overlay.appendChild(spinner); el.appendChild(overlay); // 将遮罩层附加到目标元素上 } }, updated(el, binding) { const newIsLoading = Boolean(binding.value); // 更新后的值 const oldIsLoading = Boolean(binding.oldValue); // 上一次的值 if (!newIsLoading && oldIsLoading) { const overlay = el.querySelector(&#39;.overlay&#39;); if (overlay) { el.removeChild(overlay); // 移除遮罩层 } } else if (newIsLoading && !oldIsLoading) { const overlay = document.createElement(&#39;div&#39;); overlay.className = &#39;overlay&#39;; overlay.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.8); z-index: 9999; display: flex; justify-content: center; align-items: center; `; const spinner = document.createElement(&#39;span&#39;); spinner.textContent = &#39;加载...&#39;; spinner.style.color = &#39;#4caf50&#39;; spinner.style.fontSize = &#39;16px&#39;; overlay.appendChild(spinner); el.appendChild(overlay); } } }); ``` 上述代码实现了两个生命周期钩子函数: - **beforeMount**: 当指令首次应用时触发,用于初始化加载状态并显示遮罩层[^1]。 - **updated**: 当数据更新时重新评估是否需要隐藏或显示遮罩层。 #### 使用自定义指令 在模板中可以直接使用该指令如下所示: ```html <template> <div style="height: 100%; position: relative;" v-loading="loading"> <ul> <li v-for="(item, index) in data" :key="index">{{ item }} - {{ item * 2 }}</li> </ul> </div> </template> <script> export default { data() { return { loading: true, data: [1, 2, 3, 4, 5], }; }, mounted() { setTimeout(() => { this.loading = false; // 停止加载效果 }, 3000); // 模拟异步请求耗时 } }; </script> ``` 在这个示例中,当页面加载完成或者模拟的数据获取完成后,会自动关闭加载指示器。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值