• vue3自定义全局Loading


    自定义插件之全局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

    指令的方式使用

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    函数式调用

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    自定义全局Loading

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

    添加MyLoading.vue

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    添加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
                        })
                    }
                }
            })
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

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

    • $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')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用方法一:函数式使用

    调用全局方法弹出Loading

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    image-20230925171920861

    使用方法二:指令式使用

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    使用自定义的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')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    PostgreSQL设置主键从1开始自增
    outsystems合集系列(二)
    SSM - Springboot - MyBatis-Plus 全栈体系(三十二)
    数据结构-队列(数组实现)
    spring boot 项目中的application不能执行是什么问题
    Python结合文件名称将多个文件复制到不同路径下
    [附源码]java毕业设计高考志愿智能推荐系统
    【第006篇】通过impdp命令导入dmp文件到Oracle11g数据库中
    Go-Ldap-Admin | openLDAP 同步钉钉、企业微信、飞书组织架构实践和部分小坑
    一、Prometheus集成Grafana可视化监控安装详解
  • 原文地址:https://blog.csdn.net/SongZhengxing_/article/details/133277505