vue3自定义全局Loading

news2024/11/23 20:03:10

自定义插件之全局Loading

ElementPlus的默认全局Loading

如果完整引入了 Element Plus,那么 app.config.globalProperties 上会有一个全局方法$loading,同样会返回一个 Loading 实例。

名称说明类型默认
targetLoading 需要覆盖的 DOM 节点。 可传入一个 DOM 对象或字符串; 若传入字符串,则会将其作为参数传入 document.querySelector以获取到对应 DOM 节点string / HTMLElementdocument.body
bodyv-loading 指令中的 body 修饰符booleanfalse
fullscreenv-loading 指令中的 fullscreen 修饰符booleantrue
lockv-loading 指令中的 lock 修饰符booleanfalse
text显示在加载图标下方的加载文案string
spinner自定义加载图标类名string
background遮罩背景色string
customClassLoading 的自定义类名string

指令的方式使用

<template>
   <div class="box" v-loading="isLoading">
      content
   </div>
   <el-button type="primary" @click="showDivLoading">显示loading</el-button>
</template>

<script setup lang="ts">
// 显示局部loading
let isLoading = ref(false)

const showDivLoading = () => {
  isLoading.value = !isLoading.value
}

</script>

<style scoped>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
}
</style>

函数式调用

<template>
  <el-button type="primary" @click="showLoading">showLoading</el-button>
</template>

<script setup lang="ts">
import {getCurrentInstance} from 'vue'
// 获取当前实例
const {proxy} = getCurrentInstance()

// 显示全局loading
const showLoading = () => {
  const loading = proxy.$loading()
  setTimeout(() => {
    loading.close()
  }, 2000)
}
</script>

自定义全局Loading

我们自己动手来实现一个和ElementPlus一样的Loading,同时支持函数调用和指令调用

添加MyLoading.vue

<template>
  <transition enter-active-class="animate__animated animate__fadeIn"
              leave-active-class="animate__animated animate__fadeOut">
    <div class="root-box" v-if="show">
      <div class="wrap">
        <img src="../assets/images/loading.gif"/>
      </div>
    </div>
  </transition>
</template>

<script setup>
let show = ref(false)

const showLoading = () => {
  show.value = true
}
const hideLoading = (callback) => {
  show.value = false
  callback && setTimeout(() => callback(), 500)
}

defineExpose({
  show,
  showLoading,
  hideLoading
})

</script>

<style scoped lang="scss">
.animate__animated.animate__fadeIn {
  --animate-duration: 0.5s;
}

.animate__animated.animate__fadeOut {
  --animate-duration: 0.5s;
}

.root-box {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  margin: 0;
  background-color: rgba(255, 255, 255, 0.9);
  z-index: 2000;
  display: flex;
  justify-content: center;
  align-items: center;

  .wrap {
    width: 100px;
    height: 100px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;

    img {
      width: 100%;
      transform: scale(2.5);
    }
  }
}
</style>

添加MyLoading.ts

import type {App, VNode,} from "vue"
import {createVNode, render, cloneVNode} from "vue"
import MyLoading from "@/components/MyLoading.vue"

export default {
    install(app: App) {
        // 使用vue底层的createVNode方法将组件渲染为虚拟节点
        const VNode: VNode = createVNode(MyLoading)
        // 使用render函数将组件挂载到body中
        render(VNode, document.body)
        // 定义全局方法设置组件的显示和隐藏
        app.config.globalProperties.$showLoading = VNode.component?.exposed.showLoading
        app.config.globalProperties.$hideLoading = VNode.component?.exposed.hideLoading

        const weakMap = new WeakMap()

        // 自定义Loading指令
        app.directive("zx-loading", {
            mounted(el) {
                if (weakMap.get(el)) return
                //  记录当前绑定元素的position
                weakMap.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
                    })
                }
            }
        })
    }
}

在上面的文件中定义了两个全局函数和一个自定义指令

  • $showLoading:全局显示一个Loading
  • $hideLoading:关闭全局的Loading
  • zx-loading:自定义指令

在main.ts中挂载

main.ts 中去挂载我们自定义的 Loading

import {createApp} from 'vue'
import MyLoading from "@/utils/MyLoading";

const app = createApp(App)
// 引入自定义的全局Loading
app.use(MyLoading)

app.mount('#app')

使用方法一:函数式使用

调用全局方法弹出Loading

<template>
    <!--自定义全局loading-->
    <el-button type="primary" @click="showMyLoading">显示自定义的全局loading</el-button>
</template>

<script setup lang="ts">
import {getCurrentInstance} from 'vue'
// 获取当前实例
const {proxy} = getCurrentInstance()

// 全局显示自定义loading
const showMyLoading = () => {
  proxy.$showLoading()
  setTimeout(() => {
    proxy.$hideLoading()
  }, 2000)
}
</script>

image-20230925171920861

使用方法二:指令式使用

<template>
  <div>
    <!--自定义的loading指令使用-->
    <div class="box" v-zx-loading="isLoading">
      指令的方式使用
    </div>
    <el-button type="primary" @click="showDivLoading">显示loading</el-button>

	<!--自定义的loading指令使用-->      
    <div class="parent">
      <div class="child" v-zx-loading="childLoading">
      </div>
    </div>
    <el-button type="primary" @click="showChildLoading">显示childLoading</el-button>
  </div>
</template>

<script setup lang="ts">
// 显示局部loading
let isLoading = ref(false)
const showDivLoading = () => {
  isLoading.value = !isLoading.value
}

const childLoading = ref(false)
const showChildLoading = () => {
  childLoading.value = !childLoading.value
}
</script>

<style scoped lang="scss">
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
}

.parent {
  position: relative;
  width: 300px;
  height: 300px;
  border: 1px solid;
  padding: 30px;

  .child {
    position: absolute;
    right: 30px;
    bottom: 30px;
    width: 200px;
    height: 200px;
    border: 1px solid;
  }
}
</style>

image-20230925172100385

use函数源码实现

添加 MyUse.ts

import type {App} from "vue"
import {app} from "@/main"

// 定义一个接口,声明install方法必传
interface Use {
    install: (app: App, ...options: any[]) => void
}

const installList = new Set()

export default function myUse<T extends Use>(plugin: T, ...options: any[]) {
    // 判断这个插件是否已经注册过了,如果注册过了则报错
    if (installList.has(plugin)) {
        console.error("Plugin already installed")
        return
    }
    // 调用插件身上的install方法,并传入main.ts导出的app
    plugin.install(app, ...options)
    installList.add(plugin)
}

使用自定义的myUse方法注册我们自定义的Loading

import {createApp} from 'vue'

// 自定义全局Loading
import MyLoading from "@/utils/MyLoading";
// 自定义app.use方法
import myUse from "@/utils/MyUse";


export const app = createApp(App)
// 引入自定义的全局Loading
myUse(MyLoading)

app.mount('#app')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1041593.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

田忌赛马Java

给定两个大小相等的数组 A 和 B&#xff0c;A 相对于 B 的优势可以用满足 Ai] > Bi] 的索的数目来描述。 返回 A的任意排列&#xff0c;使其相对于 B 的优势最大化. 其实核心思想就是让A中的数最小且刚好大于B中数,我们可以用链表来存储A和B中对应的数据,至于B比A中所有的数…

优优嗨聚集团:餐饮发展与房地产的关联:一种强效应的探索

随着时代的进步和经济的发展&#xff0c;餐饮业和房地产行业已成为人们日常生活中的重要组成部分。这两个行业之间存在着复杂的联系&#xff0c;它们相互影响、相互促进&#xff0c;形成了独特的经济现象。本文将从多个角度分析餐饮发展与房地产之间的关联&#xff0c;并探讨这…

苹果Vision Pro头显内置AI芯片

苹果首席执行官蒂姆库克近日在接受采访时确认&#xff0c;备受瞩目的Vision Pro头显将按计划于明年初在美国上市。这款头显被认为是苹果自iPhone以来最重要的产品之一&#xff0c;售价高达3499美元。 蒂姆库克在接受CBS Sunday Morning的采访时透露&#xff0c;他的团队对Visi…

一、浏览器输入URL会发生什么

参考链接&#xff1a;B站视频链接&#xff1a;https://www.bilibili.com/video/BV1qL411G7uj/ 本视频讲述了HTTP协议及其工作原理&#xff0c;包括HTTP协议的三次握手建立TCP连接、HTTP请求报文、HTTP响应报文等。同时&#xff0c;本视频还介绍了浏览器解析域名并建立TCP连接的…

Failed to load property source from location ‘classpath:/application.yml‘

前言 给同学部署项目的时候出现了这个错误&#xff0c;困扰我半天&#xff0c;搞了一下午&#xff0c;最后Google找到了答案。 在这里记录一下&#xff01; 解决方案 第一步&#xff1a;删除原有yml文件&#xff0c;把内容复制下来&#xff0c;重新写一个然后再粘贴进去 …

基于微信小程序的车位预定系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言用户的主要功能有&#xff1a;管理员的主要功能有&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W…

96.不同的二叉搜索树

​ 题目&#xff1a; 96. 不同的二叉搜索树 中等 2.4K 相关企业 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xf…

debian设置允许root登录

新debian安装后默认不能使用root登录&#xff0c;下文给出解决办法。 备份此文件 cp /etc/gdm3/daemon.conf /etc/gdm3/daemon.conf.bk 修改 /etc/gdm3/daemon.conf&#xff0c;在[security]下面新增AllowRoot true 保存。接着修改 /etc/pam.d/gdm-password 文件&#xff0…

Feign 使用篇

Feign是一个声明式的HTTP客户端工具&#xff0c;它简化了在分布式系统中进行服务间通信的过程。开发人员可以使用Feign来定义接口&#xff0c;然后通过该接口来调用远程服务&#xff0c;就像调用本地方法一样简单。 目录 Feign的一些关键特性和概念&#xff1a;openfeign 对比 …

算法:O(1) 时间插入、删除和获取随机元素---哈希表+动态数组

1、题目&#xff1a; 实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回 true &#xff1b;否则&#xff0c;返回 false 。bool remove(int val) 当元素…

基于jquery开发的Windows 12网页版

预览 https://win12.gitapp.cn 首页代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"refresh" content"0;urldesktop.html" /> <meta name"viewport&…

上海亚商投顾:沪指放量涨1.55% AI概念股全线爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数9月22日放量反弹&#xff0c;沪指午后涨超1%&#xff0c;重返3100点上方&#xff0c;创业板指涨超2%…

通过monorepo管理多个子项目

通过monorepo管理多个子项目 1. Monorepo模式 在Monorepo 模式下,根目录通常不建议直接安装依赖,而是通过工作区(workspaces)来管理依赖。 但是在一些情况下,在根目录安装一些共享依赖也是可以的。 在根目录安装开发相关的依赖 如TypeScript, ESLint, Jest等。这些可以被所有…

手把手教 - 开源库 libmodbus 的RTU-Master 的使用笔记

测试环境&#xff1a;基于nuc980开发板 Linux信息&#xff1a;Linux buildroot 4.4.289 #8 PREEMPT Thu Sep 21 14:29:45 CST 2023 armv5tejl GNU/Linux 目录&#xff1a; 一、libmodbus 库简介 二、下载链接 三、移植准备 四、移植过程和完整代码 五、测试结果 一、libmodbus …

虚拟机数据恢复:Stellar Data Recovery for Virtual Machine

虚拟机数据恢复-----Crack Version Stellar Data Recovery for Virtual Machine 软件可从 VMware (.vmdk)、ORACLE (.vdi) 和 Microsoft (.vhd) 虚拟映像文件中恢复丢失和删除的数据。 从 VMDK、VDI 和 VHD 虚拟映像文件中恢复数据提供原始恢复选项来恢复数据从已删除或无法识…

太阳能供电模块

基于Solar Cell的锂电池充放电模块 由于一些需求&#xff0c;最近做了一款基于太阳能的锂电池充放电模块。该模块能够利用太阳能为锂电池充电和为负载提供5V的电压&#xff0c;在太阳能不充足的条件下&#xff0c;由锂电池提供需要的能量。 主要思路是将太阳能板获得的能量存储…

嵌入式Linux学习(1)——通信总线协议简介

目录 一. UART 1.1 单工/双工通信 ​编辑 1.2 UART帧格式 1.2.1 Q/A 1.3 UART硬件结构 二. 基于UART的协议 2.1 RS232 2.1.1 RS232协议存在的问题 2.2 RS485 2.2.1 差分信号 2.2.2 RS485优势 三. IIC 3.1 通信过程 3.2 IIC总线寻址 3.3 IIC总线信号 3.3.1 起始…

USB转2路RS422串口

基于USB转2路串口芯片CH342&#xff0c;可以为各类主机扩展出2个独立的串口。CH342芯片支持使用操作系统内置的CDC串口驱动&#xff0c;也支持使用厂商提供的VCP串口驱动程序&#xff0c;可支持Windows、Linux、Android、macOS等操作系统。因CDC类协议和类驱动的原因&#xff0…

多通道振弦数据记录仪在预防地质灾害中的重要性

多通道振弦数据记录仪在预防地质灾害中的重要性 地质灾害是指在地表或岩体内部发生的、由地质原因引起的、对人类生命、财产和环境安全造成威胁或损害的各种灾害。地质灾害的预测和预防对于保障人民生命财产安全、维护社会稳定和可持续发展具有重要的意义。而多通道振弦数据记…