diff --git a/packages/loading/__tests__/loading.spec.ts b/packages/loading/__tests__/loading.spec.ts index 79446e66cb..bee021f965 100644 --- a/packages/loading/__tests__/loading.spec.ts +++ b/packages/loading/__tests__/loading.spec.ts @@ -268,6 +268,8 @@ describe('Loading', () => { `, }) + await nextTick() + await nextTick() const maskDisplay = getComputedStyle(wrapper.find('.el-loading-mask').element).display expect(maskDisplay).toBe('block') }) diff --git a/packages/loading/src/createLoadingComponent.ts b/packages/loading/src/createLoadingComponent.ts index 76b09d1cb4..c0dc1c8576 100644 --- a/packages/loading/src/createLoadingComponent.ts +++ b/packages/loading/src/createLoadingComponent.ts @@ -2,7 +2,10 @@ import { createVNode, h, reactive, ref, render, toRefs, Transition, VNode, vShow import { removeClass } from '@element-plus/utils/dom' import type { ILoadingCreateComponentParams, ILoadingInstance } from './loading.type' -export function createLoadingComponent({ options , globalLoadingOption }: ILoadingCreateComponentParams): ILoadingInstance { +export function createLoadingComponent({ + options, + globalLoadingOption, +}: ILoadingCreateComponentParams): ILoadingInstance { let vm: VNode = null let afterLeaveTimer: Nullable = null @@ -11,7 +14,7 @@ export function createLoadingComponent({ options , globalLoadingOption }: ILoadi ...options, originalPosition: '', originalOverflow: '', - visible: options.hasOwnProperty('visible') ? options.visible : true, + visible: false, }) function setText(text: string) { @@ -20,8 +23,15 @@ export function createLoadingComponent({ options , globalLoadingOption }: ILoadi function destroySelf() { const target = data.parent - if(!target.vLoadingAddClassList) { - removeClass(target, 'el-loading-parent--relative') + if (!target.vLoadingAddClassList) { + let loadingNumber: number | string = target.getAttribute('loading-number') + loadingNumber = Number.parseInt(loadingNumber) - 1 + if (!loadingNumber) { + removeClass(target, 'el-loading-parent--relative') + target.removeAttribute('loading-number') + } else { + target.setAttribute('loading-number', loadingNumber.toString()) + } removeClass(target, 'el-loading-parent--hidden') } if (vm.el && vm.el.parentNode) { @@ -53,7 +63,7 @@ export function createLoadingComponent({ options , globalLoadingOption }: ILoadi destroySelf() } - const componetSetupConfig = { + const componentSetupConfig = { ...toRefs(data), setText, close, @@ -63,7 +73,7 @@ export function createLoadingComponent({ options , globalLoadingOption }: ILoadi const elLoadingComponent = { name: 'ElLoading', setup() { - return componetSetupConfig + return componentSetupConfig }, render() { const spinner = h('svg', { @@ -108,9 +118,9 @@ export function createLoadingComponent({ options , globalLoadingOption }: ILoadi render(vm, document.createElement('div')) return { - ...componetSetupConfig, + ...componentSetupConfig, vm, - get $el(){ + get $el() { return vm.el as HTMLElement }, } diff --git a/packages/loading/src/directive.ts b/packages/loading/src/directive.ts index 0a62080850..a27b7829ee 100644 --- a/packages/loading/src/directive.ts +++ b/packages/loading/src/directive.ts @@ -14,7 +14,7 @@ const createInstance = (el, binding) => { fullscreen: !!binding.modifiers.fullscreen, target: !!binding.modifiers.fullscreen ? null : el, body: !!binding.modifiers.body, - visible: !!binding.value, + visible: true, lock: !!binding.modifiers.lock, }) } diff --git a/packages/loading/src/index.ts b/packages/loading/src/index.ts index 886437041d..26c21a56c4 100644 --- a/packages/loading/src/index.ts +++ b/packages/loading/src/index.ts @@ -1,5 +1,6 @@ +import { nextTick } from 'vue' import { createLoadingComponent } from './createLoadingComponent' -import type { ILoadingOptions, ILoadingInstance, ILoadingGlobalConfig } from './loading.type' +import type { ILoadingGlobalConfig, ILoadingInstance, ILoadingOptions } from './loading.type' import { addClass, getStyle, removeClass } from '@element-plus/utils/dom' import PopupManager from '@element-plus/utils/popup-manager' import isServer from '@element-plus/utils/isServer' @@ -19,14 +20,20 @@ const globalLoadingOption: ILoadingGlobalConfig = { fullscreenLoading: null, } -const addStyle = (options: ILoadingOptions, parent: HTMLElement, instance: ILoadingInstance) => { +const addStyle = async (options: ILoadingOptions, parent: HTMLElement, instance: ILoadingInstance) => { const maskStyle: Partial = {} if (options.fullscreen) { instance.originalPosition.value = getStyle(document.body, 'position') instance.originalOverflow.value = getStyle(document.body, 'overflow') maskStyle.zIndex = String(PopupManager.nextZIndex()) } else if (options.body) { - instance.originalPosition.value = getStyle(document.body, 'position'); + instance.originalPosition.value = getStyle(document.body, 'position') + /** + * await dom render when visible is true in init, + * because some component's height maybe 0. + * e.g. el-table. + */ + await nextTick(); ['top', 'left'].forEach(property => { const scroll = property === 'top' ? 'scrollTop' : 'scrollLeft' maskStyle[property] = (options.target as HTMLElement).getBoundingClientRect()[property] + @@ -59,8 +66,8 @@ const addClassList = (options: ILoadingOptions, parent: HTMLElement, instance: I } } -const Loading = function(options: ILoadingOptions = {}): ILoadingInstance{ - if(isServer) return +const Loading = function (options: ILoadingOptions = {}): ILoadingInstance { + if (isServer) return options = { ...defaults, ...options, @@ -95,7 +102,29 @@ const Loading = function(options: ILoadingOptions = {}): ILoadingInstance{ addClassList(options, parent, instance) } + /** + * add loading-number to parent. + * because if a fullscreen loading is triggered when somewhere + * a v-loading.body was triggered before and it's parent is + * document.body which with a margin , the fullscreen loading's + * destroySelf function will remove 'el-loading-parent--relative', + * and then the position of v-loading.body will be error. + */ + let loadingNumber: number | string = parent.getAttribute('loading-number') + if (!loadingNumber) { + loadingNumber = 1 + } else { + loadingNumber = Number.parseInt(loadingNumber) + 1 + } + parent.setAttribute('loading-number', loadingNumber.toString()) + parent.appendChild(instance.$el) + + // after instance render, then modify visible to trigger transition + nextTick().then(() => { + instance.visible.value = options.hasOwnProperty('visible') ? options.visible : true + }) + if (options.fullscreen) { globalLoadingOption.fullscreenLoading = instance }