content.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. <script lang="ts" setup>
  2. import type {
  3. RouteLocationNormalizedLoaded,
  4. RouteLocationNormalizedLoadedGeneric,
  5. } from 'vue-router';
  6. import { type VNode } from 'vue';
  7. import { RouterView } from 'vue-router';
  8. import { useContentHeight } from '@vben/hooks';
  9. import { preferences, usePreferences } from '@vben/preferences';
  10. import { storeToRefs, useTabbarStore } from '@vben/stores';
  11. import { VbenSpinner } from '@vben-core/shadcn-ui';
  12. import { IFrameRouterView } from '../../iframe';
  13. import { useContentSpinner } from './use-content-spinner';
  14. defineOptions({ name: 'LayoutContent' });
  15. const tabbarStore = useTabbarStore();
  16. const { keepAlive } = usePreferences();
  17. const { spinning } = useContentSpinner();
  18. const { contentStyles } = useContentHeight();
  19. const { getCachedTabs, getExcludeCachedTabs, renderRouteView } =
  20. storeToRefs(tabbarStore);
  21. // 页面切换动画
  22. function getTransitionName(_route: RouteLocationNormalizedLoaded) {
  23. // 如果偏好设置未设置,则不使用动画
  24. const { tabbar, transition } = preferences;
  25. const transitionName = transition.name;
  26. if (!transitionName || !transition.enable) {
  27. return;
  28. }
  29. // 标签页未启用或者未开启缓存,则使用全局配置动画
  30. if (!tabbar.enable || !keepAlive) {
  31. return transitionName;
  32. }
  33. // 如果页面已经加载过,则不使用动画
  34. // if (route.meta.loaded) {
  35. // return;
  36. // }
  37. // 已经打开且已经加载过的页面不使用动画
  38. // const inTabs = getCachedTabs.value.includes(route.name as string);
  39. // return inTabs && route.meta.loaded ? undefined : transitionName;
  40. return transitionName;
  41. }
  42. /**
  43. * 转换组件,自动添加 name
  44. * @param component
  45. */
  46. function transformComponent(
  47. component: VNode,
  48. route: RouteLocationNormalizedLoadedGeneric,
  49. ) {
  50. const routeName = route.name as string;
  51. // 如果组件没有 name,则直接返回
  52. if (!routeName) {
  53. return component;
  54. }
  55. const componentName = (component.type as any).name;
  56. // 已经设置过 name,则直接返回
  57. if (componentName) {
  58. return component;
  59. }
  60. // componentName 与 routeName 一致,则直接返回
  61. if (componentName === routeName) {
  62. return component;
  63. }
  64. // 设置 name
  65. component.type ||= {};
  66. (component.type as any).name = routeName;
  67. return component;
  68. }
  69. </script>
  70. <template>
  71. <div class="relative h-full">
  72. <VbenSpinner
  73. v-if="preferences.transition.loading"
  74. :spinning="spinning"
  75. :style="contentStyles"
  76. />
  77. <IFrameRouterView />
  78. <RouterView v-slot="{ Component, route }">
  79. <Transition :name="getTransitionName(route)" appear mode="out-in">
  80. <KeepAlive
  81. v-if="keepAlive"
  82. :exclude="getExcludeCachedTabs"
  83. :include="getCachedTabs"
  84. >
  85. <component
  86. :is="transformComponent(Component, route)"
  87. v-if="renderRouteView"
  88. v-show="!route.meta.iframeSrc"
  89. :key="route.fullPath"
  90. />
  91. </KeepAlive>
  92. <component
  93. :is="Component"
  94. v-else-if="renderRouteView"
  95. :key="route.fullPath"
  96. />
  97. </Transition>
  98. </RouterView>
  99. </div>
  100. </template>