背景

在一些dialog弹窗提交场景下,有时需要等待提交完成才能继续后面的流程,而且dialog弹窗不能做任何操作,由此需要添加一个覆盖整个dialog弹窗的loading效果,,但是element提供的v-loading指令无法直接作用在dialog上面。

方法一: 自定义一个指令

优点:通用性更强

缺点:自己写的,技术不够,可能会影响性能😅

实现如下:

// directive
app.directive('dialog-loading', {
  mounted: (el, binding) => {
    nextTick(() => {
      const dialogEl = el.querySelector('.el-dialog');
      const mask = document.createElement('div');
      mask.className = 'dialog-loading-mask';

      mask.setAttribute(
        'style',
        `
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  visibility: hidden;
  background-color: rgb(255 255 255 / 90%);
  z-index: 9999;
  `
      );
      dialogEl.appendChild(mask);
      const app = createApp(Loading);
      app.mount(mask);
    });
  },
  updated: (el, binding) => {
    const loadingMask = el.querySelector('.dialog-loading-mask');
    if (!loadingMask) return;
    loadingMask.style.visibility = binding.value ? 'visible' : 'hidden';
  },
});

// Loading.vue
<template>
  <svg class="circular" viewBox="0 0 50 50">
    <circle class="path" cx="25" cy="25" r="20" fill="none" />
  </svg>
</template>

<style lang="scss" scoped>
  .circular {
    display: inline;
    width: 42px;
    height: 42px;
    animation: loading-rotate 2s linear infinite;
    .path {
      animation: loading-dash 1.5s ease-in-out infinite;
      stroke-dasharray: 90, 150;
      stroke-dashoffset: 0;
      stroke-width: 2;
      stroke: var(-- el-color-primary);
      stroke-linecap: round;
    }
  }
</style>

使用方法

在el-dialog外面套一层div,在div上添加v-dialog-loading指令,传入loading参数。

方法二:使用Elment Plus提供的ElLoading方法

优点:比较灵活,在每个需要的地方可以单独修改

缺点:每个地方都要单独加,代码量增加,不够通用

实现如下:

<script setup>
import { ElLoading } from 'element-plus'

let loadingInstance
  nextTick(() => {
    // 获取到最外层的遮罩
    const overlay = document.querySelector('.scalling-dialog');
    // 获取dialog弹窗的内容部分
    const el = overlay?.querySelector('.el-dialog');
    // 开启loading
    loadingInstance = ElLoading.service({ fullscreen: false, target: el })
    
    // 关闭loading
    // loadingInstance.close()
  })
</script>

<template>
  <el-dialog modal-class="scalling-dialog">xxx</el-dialog>
</template>