content.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <script lang="ts" setup>
  2. import type { VNode } from 'vue';
  3. import type {
  4. RouteLocationNormalizedLoaded,
  5. RouteLocationNormalizedLoadedGeneric,
  6. } from 'vue-router';
  7. import { computed } from 'vue';
  8. import { RouterView } from 'vue-router';
  9. import { preferences, usePreferences } from '@vben/preferences';
  10. import { storeToRefs, useTabbarStore } from '@vben/stores';
  11. import { IFrameRouterView } from '../../iframe';
  12. defineOptions({ name: 'LayoutContent' });
  13. const tabbarStore = useTabbarStore();
  14. const { keepAlive } = usePreferences();
  15. const { getCachedTabs, getExcludeCachedTabs, renderRouteView } =
  16. storeToRefs(tabbarStore);
  17. /**
  18. * 是否使用动画
  19. */
  20. const getEnabledTransition = computed(() => {
  21. const { transition } = preferences;
  22. const transitionName = transition.name;
  23. return transitionName && transition.enable;
  24. });
  25. // 页面切换动画
  26. function getTransitionName(_route: RouteLocationNormalizedLoaded) {
  27. // 如果偏好设置未设置,则不使用动画
  28. const { tabbar, transition } = preferences;
  29. const transitionName = transition.name;
  30. if (!transitionName || !transition.enable) {
  31. return;
  32. }
  33. // 标签页未启用或者未开启缓存,则使用全局配置动画
  34. if (!tabbar.enable || !keepAlive) {
  35. return transitionName;
  36. }
  37. // 如果页面已经加载过,则不使用动画
  38. // if (route.meta.loaded) {
  39. // return;
  40. // }
  41. // 已经打开且已经加载过的页面不使用动画
  42. // const inTabs = getCachedTabs.value.includes(route.name as string);
  43. // return inTabs && route.meta.loaded ? undefined : transitionName;
  44. return transitionName;
  45. }
  46. /**
  47. * 转换组件,自动添加 name
  48. * @param component
  49. */
  50. function transformComponent(
  51. component: VNode,
  52. route: RouteLocationNormalizedLoadedGeneric,
  53. ) {
  54. // 组件视图未找到,如果有设置后备视图,则返回后备视图,如果没有,则抛出错误
  55. if (!component) {
  56. console.error(
  57. 'Component view not found,please check the route configuration',
  58. );
  59. return undefined;
  60. }
  61. const routeName = route.name as string;
  62. // 如果组件没有 name,则直接返回
  63. if (!routeName) {
  64. return component;
  65. }
  66. const componentName = (component?.type as any)?.name;
  67. // 已经设置过 name,则直接返回
  68. if (componentName) {
  69. return component;
  70. }
  71. // componentName 与 routeName 一致,则直接返回
  72. if (componentName === routeName) {
  73. return component;
  74. }
  75. // 设置 name
  76. component.type ||= {};
  77. (component.type as any).name = routeName;
  78. return component;
  79. }
  80. </script>
  81. <template>
  82. <div class="relative h-full">
  83. <IFrameRouterView />
  84. <RouterView v-slot="{ Component, route }">
  85. <Transition
  86. v-if="getEnabledTransition"
  87. :name="getTransitionName(route)"
  88. appear
  89. mode="out-in"
  90. >
  91. <KeepAlive
  92. v-if="keepAlive"
  93. :exclude="getExcludeCachedTabs"
  94. :include="getCachedTabs"
  95. >
  96. <component
  97. :is="transformComponent(Component, route)"
  98. v-if="renderRouteView"
  99. v-show="!route.meta.iframeSrc"
  100. :key="route.fullPath"
  101. />
  102. </KeepAlive>
  103. <component
  104. :is="Component"
  105. v-else-if="renderRouteView"
  106. :key="route.fullPath"
  107. />
  108. </Transition>
  109. <template v-else>
  110. <KeepAlive
  111. v-if="keepAlive"
  112. :exclude="getExcludeCachedTabs"
  113. :include="getCachedTabs"
  114. >
  115. <component
  116. :is="transformComponent(Component, route)"
  117. v-if="renderRouteView"
  118. v-show="!route.meta.iframeSrc"
  119. :key="route.fullPath"
  120. />
  121. </KeepAlive>
  122. <component
  123. :is="Component"
  124. v-else-if="renderRouteView"
  125. :key="route.fullPath"
  126. />
  127. </template>
  128. </RouterView>
  129. </div>
  130. </template>