【踩坑日记】vue项目实现弹框整体loading效果(包括标题)

使用elementUI的Loading.service实现弹框全覆盖效果的loading遮罩,并把它写成vue插件,在页面直接使用v-dialogLoading指令去显示与隐藏遮罩。

需求背景:需要实现项目中所有弹框的loading遮罩只显示弹框上,在其他地方不加遮罩。

小声逼逼!!:客户觉得原本的loading遮罩是全页面的会让业务人员觉得弹框底下的页面也在刷新(他们并不想原页面刷新)(我也反复强调过,下面的页面是不刷新的。跟他们说过后给我的答复是有人觉得全屏遮罩太丑了,他们就想要在弹框上loading…),无奈…没办法,硬着头皮干吧…谁让他们是金主爸爸呢

在这里插入图片描述

实现方案

最开始想的方案是,改弹窗的css代码,让它达到弹框的大小,欸,这不是轻松愉快的解决了吗?
当我打开它的样式代码后才发现,(傻眼),怎么是个绝对定位,这要设置位置大小,朕应该怎么拿得到呢?每个弹窗的大小位置也有可能不一样啊(汗流浃背)发现问题并不那么简单,快快打开朕的最强Ai,问了下,也是css?还得用上原生事件?这么麻烦?果断pass,不是我不会噢,我真是觉得它给的不好(确信)。罢了,罢了,朕还是自己动手搜搜看吧。

一搜 欸 看到了这个vue使用elementPlus ui框架,如何给Dialog 对话框添加Loading 自定义类名显示

不错不错,但是他是用的vue3+elementPlus Ui,我这个项目是vue2+element,看了下官方文档,欸,这一块好像老的也支持(喜滋滋)这不是轻松愉快就搞定了吗(嘻嘻)
在这里插入图片描述

那就赶紧撸起袖子加油干!!

具体实现

看文档,首先得给弹框加一个类名
文档
然后我又是要全局生效,我肯定得自己自定义一个指令来控制它是否生效,所以模板代码就应该是这样:
代码片段
自定义指定代码如下:
1.新增一个dialog-loading.js文件

// 导入 Element UI 的 Loading 组件,用于创建加载指示器
import { Loading } from 'element-ui';

// 定义一个 Vue 插件对象
export default {
    // install 方法是 Vue 插件的入口点,Vue 会在使用 Vue.use() 注册插件时调用它
    install(Vue) {
        // 在 Vue 的原型上定义一个全局数组,用来存储所有的活动加载实例
        Vue.prototype.$activeLoadings = [];

        // 向 Vue 添加一个全局混入(mixin),这会影响每一个 Vue 实例
        Vue.mixin({
            // 混入的数据部分,定义了一个 loadingClassName 变量,用于存储当前加载指示器的类名
            data() {
                return {
                    loadingClassName: null,
                };
            },
            // 混入的方法部分
            methods: {
                // 显示加载指示器的方法
                async showLoading() {
                    // 生成一个基于时间和随机数的唯一类名,确保每次加载指示器的类名都不相同
                    const uniqueClassName = `loading-${Date.now()}-${Math.floor(Math.random() * 10000)}`;

                    // 将新生成的类名赋值给实例的 loadingClassName 属性
                    this.loadingClassName = uniqueClassName;
                    // 等待 Vue 的 DOM 更新完成
                    await this.$nextTick(); 

                    // 在当前组件的根元素下查找第一个拥有 .loading-class 类名的元素
                    console.log(this.$el.querySelector('.loading-class'))
                    // 为找到的元素添加新生成的类名
                    this.$el.querySelector('.loading-class').classList.add(uniqueClassName);

                    // 使用 Element UI 的 Loading.service 创建一个新的加载实例,目标为新添加的类名元素,并设置背景色
                    const loadingInstance = Loading.service({
                        target: '.' + uniqueClassName,
                        background: 'rgba(255, 255, 255, 0.9)',
                    });

                    // 将新的加载实例信息(类名和实例自身)存入全局数组
                    this.$activeLoadings.push({ className: uniqueClassName, instance: loadingInstance });
                },
                // 隐藏加载指示器的方法
                async hideLoading() {
                    // 如果有当前正在使用的 loadingClassName
                    if (this.loadingClassName) {
                        // 等待 Vue 的 DOM 更新完成
                        await this.$nextTick();

                        // 从全局数组中找到与当前 loadingClassName 匹配的加载实例
                        const loadingInstance = this.$activeLoadings.find(
                            (item) => item.className === this.loadingClassName
                        );

                        // 如果找到了匹配的实例
                        if (loadingInstance) {
                            // 关闭该加载实例
                            loadingInstance.instance.close();
                            // 从全局数组中移除已关闭的实例
                            this.$activeLoadings = this.$activeLoadings.filter(
                                (item) => item.className !== this.loadingClassName
                            );
                            // 从当前组件的根元素中移除 loadingClassName 类名
                            this.$el.classList.remove(this.loadingClassName);
                            // 清空 loadingClassName,表示当前没有加载指示器在显示
                            this.loadingClassName = null;
                        }
                    }
                },
            },
        });

        // 定义一个名为 dialogLoading 的自定义指令
        Vue.directive('dialogLoading', {
            // 当指令绑定到元素上时触发
            bind(el, binding, vnode) {
                // 如果指令的值为真,则显示加载指示器
                if (binding.value) {
                    vnode.context.showLoading();
                }
            },
            // 当指令绑定的值发生变化时触发
            update(el, binding, vnode) {
                // 如果新旧值不等,则根据新值决定显示或隐藏加载指示器
                if (binding.value !== binding.oldValue) {
                    if (binding.value) {
                        vnode.context.$nextTick(() => {
                            vnode.context.showLoading();
                        });
                    } else {
                        vnode.context.$nextTick(() => {
                            vnode.context.hideLoading();
                        });
                    }
                }
            },
            // 当指令与元素解除绑定时触发
            unbind(el, binding, vnode) {
                // 隐藏加载指示器
                vnode.context.hideLoading();
            },
        });
    },
};

2.在main.js里引入

// 自定义弹框loading
import dialogLoading from './common/dialog-loading.js';
Vue.use(dialogLoading);

效果实现

效果图

注意

1.this.$el通常指的是Vue组件的根元素,而不是所有子元素。
2.loading的关闭时间应当大于接口的setTimeout时间,不然下一次调用会出现loading的没生效,那是因为上一次的loading还未关闭。
3.target的类名必须是唯一的。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你怎么在吐泡泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值