fix: iframe spinner

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

View File

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

View File

@ -1,6 +1,4 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { TimeoutHandle } from '@vben/types';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
interface Props { interface Props {
@ -20,11 +18,12 @@ defineOptions({
}); });
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
minLoadingTime: 200, minLoadingTime: 50,
}); });
const startTime = ref(0); const startTime = ref(0);
const showSpinner = ref(false); const showSpinner = ref(false);
const timer = ref<TimeoutHandle>(); const renderSpinner = ref(true);
const timer = ref<ReturnType<typeof setTimeout>>();
watch( watch(
() => props.spinning, () => props.spinning,
@ -39,18 +38,29 @@ watch(
const loadingTime = performance.now() - startTime.value; const loadingTime = performance.now() - startTime.value;
showSpinner.value = loadingTime > props.minLoadingTime; showSpinner.value = loadingTime > props.minLoadingTime;
if (showSpinner.value) {
renderSpinner.value = true;
}
}, props.minLoadingTime); }, props.minLoadingTime);
}, },
{ {
immediate: true, immediate: true,
}, },
); );
function onTransitionEnd() {
renderSpinner.value = false;
}
</script> </script>
<template> <template>
<div <div
v-if="showSpinner" v-if="renderSpinner"
class="flex-center bg-overlay absolute left-0 top-0 size-full backdrop-blur-sm" :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 <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-['']" 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> <script lang="ts" setup>
import { computed, ref } from 'vue'; import type { RouteLocationNormalized } from 'vue-router';
import { type RouteLocationNormalized, useRoute } 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 { preferences } from '@vben-core/preferences';
import { Spinner } from '@vben-core/shadcn-ui';
import { useTabsStore } from '@vben-core/stores'; import { useTabsStore } from '@vben-core/stores';
defineOptions({ name: 'IFrameRouterView' }); defineOptions({ name: 'IFrameRouterView' });
const spinning = ref(true); const spinningList = ref<boolean[]>([]);
const tabsStore = useTabsStore(); const tabsStore = useTabsStore();
const route = useRoute(); const route = useRoute();
@ -53,23 +55,30 @@ function canRender(tabItem: RouteLocationNormalized) {
return tabsStore.getTabs.some((tab) => tab.name === name); return tabsStore.getTabs.some((tab) => tab.name === name);
} }
function hideLoading() { function hideLoading(index: number) {
spinning.value = false; spinningList.value[index] = false;
}
function showSpinning(index: number) {
const curSpinning = spinningList.value[index];
// loading
return curSpinning === undefined ? true : curSpinning;
} }
</script> </script>
<template> <template>
<template v-if="showIframe"> <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 <div
v-show="routeShow(item)" v-show="routeShow(item)"
v-if="canRender(item)" v-if="canRender(item)"
class="relative size-full" class="relative size-full"
> >
<Spinner :spinning="spinning" /> <Spinner :spinning="showSpinning(index)" />
<iframe <iframe
:src="item.meta.iframeSrc as string" :src="item.meta.iframeSrc as string"
class="size-full" class="size-full"
@load="hideLoading" @load="hideLoading(index)"
></iframe> ></iframe>
</div> </div>
</template> </template>