fix: iframe spinner

This commit is contained in:
vben 2024-06-08 22:46:22 +08:00
parent dcc1fcd528
commit fcf4b9ae5b
5 changed files with 47 additions and 22 deletions

View File

@ -23,7 +23,7 @@ async function initApplication() {
await bootstrap(namespace);
// 移除并销毁loading
destoryAppLoading();
destroyAppLoading();
}
/**
@ -31,23 +31,28 @@ async function initApplication() {
* index.html app标签内
* css动画隐藏loading节点来改善体验
*/
function destoryAppLoading() {
// 全局搜索文件 loading.html, 找到对应的节点
function destroyAppLoading() {
// 查找全局 loading 元素
const loadingElement = document.querySelector('#__app-loading__');
if (loadingElement) {
// 添加隐藏类,触发过渡动画
loadingElement.classList.add('hidden');
// 查找所有需要移除的注入 loading 元素
const injectLoadingElements = document.querySelectorAll(
'[data-app-loading^="inject"]',
);
// 过渡动画结束后移除loading节点
// 当过渡动画结束时,移除 loading 元素和所有注入的 loading 元素
loadingElement.addEventListener(
'transitionend',
() => {
loadingElement.remove();
injectLoadingElements.forEach((el) => el?.remove());
loadingElement.remove(); // 移除 loading 元素
injectLoadingElements.forEach((el) => el.remove()); // 移除所有注入的 loading 元素
},
{ once: true },
);
); // 确保事件只触发一次
}
}

View File

@ -19,6 +19,7 @@ export * from './pin-input';
export * from './popover';
export * from './segmented';
export * from './sheet';
export * from './spinner';
export * from './tooltip';
export * from './ui/alert-dialog';
export * from './ui/avatar';

View File

@ -1,6 +1,4 @@
<script lang="ts" setup>
import type { TimeoutHandle } from '@vben/types';
import { ref, watch } from 'vue';
interface Props {
@ -20,11 +18,12 @@ defineOptions({
});
const props = withDefaults(defineProps<Props>(), {
minLoadingTime: 200,
minLoadingTime: 50,
});
const startTime = ref(0);
const showSpinner = ref(false);
const timer = ref<TimeoutHandle>();
const renderSpinner = ref(true);
const timer = ref<ReturnType<typeof setTimeout>>();
watch(
() => props.spinning,
@ -39,18 +38,29 @@ watch(
const loadingTime = performance.now() - startTime.value;
showSpinner.value = loadingTime > props.minLoadingTime;
if (showSpinner.value) {
renderSpinner.value = true;
}
}, props.minLoadingTime);
},
{
immediate: true,
},
);
function onTransitionEnd() {
renderSpinner.value = false;
}
</script>
<template>
<div
v-if="showSpinner"
class="flex-center bg-overlay absolute left-0 top-0 size-full backdrop-blur-sm"
v-if="renderSpinner"
:class="{
'invisible opacity-0': !showSpinner,
}"
class="flex-center bg-overlay absolute left-0 top-0 size-full backdrop-blur-sm transition-all duration-500"
@transitionend="onTransitionEnd"
>
<div
class="loader before:bg-primary/50 after:bg-primary relative h-12 w-12 before:absolute before:left-0 before:top-[60px] before:h-[5px] before:w-12 before:animate-[loader-shadow-ani_0.5s_linear_infinite] before:rounded-[50%] before:content-[''] after:absolute after:left-0 after:top-0 after:h-full after:w-full after:animate-[loader-jump-ani_0.5s_linear_infinite] after:rounded after:content-['']"

View File

@ -1,14 +1,16 @@
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { type RouteLocationNormalized, useRoute } from 'vue-router';
import type { RouteLocationNormalized } from 'vue-router';
import { computed, ref } from 'vue';
import { useRoute } from 'vue-router';
import { Spinner } from '@vben/common-ui';
import { preferences } from '@vben-core/preferences';
import { Spinner } from '@vben-core/shadcn-ui';
import { useTabsStore } from '@vben-core/stores';
defineOptions({ name: 'IFrameRouterView' });
const spinning = ref(true);
const spinningList = ref<boolean[]>([]);
const tabsStore = useTabsStore();
const route = useRoute();
@ -53,23 +55,30 @@ function canRender(tabItem: RouteLocationNormalized) {
return tabsStore.getTabs.some((tab) => tab.name === name);
}
function hideLoading() {
spinning.value = false;
function hideLoading(index: number) {
spinningList.value[index] = false;
}
function showSpinning(index: number) {
const curSpinning = spinningList.value[index];
// loading
return curSpinning === undefined ? true : curSpinning;
}
</script>
<template>
<template v-if="showIframe">
<template v-for="item in iframeRoutes" :key="item.fullPath">
{{ iframeRoutes.length }}
<template v-for="(item, index) in iframeRoutes" :key="item.fullPath">
<div
v-show="routeShow(item)"
v-if="canRender(item)"
class="relative size-full"
>
<Spinner :spinning="spinning" />
<Spinner :spinning="showSpinning(index)" />
<iframe
:src="item.meta.iframeSrc as string"
class="size-full"
@load="hideLoading"
@load="hideLoading(index)"
></iframe>
</div>
</template>