想法: 本来是想简单的通过对指令的绑定节点设置相对定位然后在其子级创建loading组件覆盖原有元素,但考虑到强制改变节点样式可能对原有样式产生干扰,于是有了新的想法。
import { render, h } from 'vue'
import { Spin } from 'ant-design-vue';
const mount = (el: HTMLElement): void => {
el.childNodes.forEach((item: any) => {
item.style && (item.style.opacity = '0')
})
// 绑定节点下创建子节点
let parent: HTMLElement | null = el.querySelector('#__LOADING_PARENT__')
if (!parent) {
parent = document.createElement('div')
parent.style.position = 'relative'
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',
left: `-${elStyle.paddingLeft}`,
width: `${el.clientWidth}px`,
height: `${el.clientHeight}px`,
backgroundColor: 'rgba(0, 0, 0, 0.3)',
opacity: 1,
zIndex: 1000
}
render(h(Spin, { class: 'directive-loading', tip: '加载中...', size: 'large', style }), parent)
}
const unmount = (el: HTMLElement) => {
el.childNodes.forEach((item: any) => {
item.style && (item.style.opacity = '1')
})
const loading: HTMLElement | null = el.querySelector('#__LOADING_PARENT__')
if (!loading) return
el.removeChild(loading)
}
export default {
// 在绑定元素的父组件 及他自己的所有子节点都挂载完成后调用
mounted: (el: HTMLElement, binding: any) => {
binding.value && mount(el)
},
// 在绑定元素的父组件 及他自己的所有子节点都更新后调用
updated: (el: HTMLElement, binding: any) => {
binding.value ? mount(el) : unmount(el)
}
}