想法: 本来是想简单的通过对指令的绑定节点设置相对定位然后在其子级创建loading组件覆盖原有元素,但考虑到强制改变节点样式可能对原有样式产生干扰,于是有了新的想法。

/**
 * 方框内添加loading UI提示
 * 自定义属性传入boolean数据类型进行控制
 */

import { render, h } from 'vue'
import { Spin } from 'ant-design-vue';
const mount = (el: HTMLElement): void => {
  let parent: HTMLElement | null = el.querySelector('#__LOADING_PARENT__')
  if (!parent) {
    parent = document.createElement('div')
    parent.style.position = 'relative'
    parent.style.alignSelf = 'flex-start'
    parent.id = '__LOADING_PARENT__'
    if (el.firstChild) {
      el.insertBefore(parent, el.firstChild)
    } else {
      el.appendChild(parent)
    }
  }
  parent.style.opacity = '1'
  const elStyle = window.getComputedStyle(el, null)
  const style = {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    position: 'absolute',
    flexDirection: 'column',
    top: `-${elStyle.paddingTop}`,
    left: `-${elStyle.paddingLeft}`,
    width: `${el.clientWidth}px`,
    height: `${el.clientHeight}px`,
    backgroundColor: 'rgba(255, 255, 255, .5)',
    opacity: 1,
    zIndex: 1000
  }
  render(h(Spin, { class: 'directive-loading', tip: '加载中...', size: 'large', style }), parent)
}
const unmount = (el: HTMLElement) => {
  const loading: HTMLElement | null = el.querySelector('#__LOADING_PARENT__')
  if (loading && loading.parentNode === el) {
    el.removeChild(loading)
  }
}
export default {
  // 在绑定元素的父组件 及他自己的所有子节点都挂载完成后调用
  mounted: (el: HTMLElement, binding: any) => {
    binding.value && mount(el)
  },
  // 在绑定元素的父组件 及他自己的所有子节点都更新后调用
  updated: (el: HTMLElement, binding: any) => {
    setTimeout(() => {
      binding.value ? mount(el) : unmount(el)
    })
  }
}

更多推荐