index.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <template>
  2. <el-scrollbar wrap-class="scroll-wrap">
  3. <div class="vue-shop-vite-box" :class="{ mobile }">
  4. <component :is="layout" :collapse="collapse" :device="device" :fixed-header="theme.fixedHeader" :show-tabs="theme.showTabs" />
  5. </div>
  6. <vab-theme-drawer />
  7. <vab-theme-setting />
  8. <vab-statistics />
  9. <el-backtop target="#app .scroll-wrap" />
  10. </el-scrollbar>
  11. </template>
  12. <script lang="ts" setup>
  13. import { useSettingsStore } from '/@/store/modules/settings'
  14. import { convertToCamelCase } from '/@/utils/convertToCamelCase'
  15. defineOptions({
  16. name: 'Layout',
  17. })
  18. interface ComponentType {
  19. default: Component
  20. }
  21. const settingsStore = useSettingsStore()
  22. const { device, collapse, theme } = storeToRefs(settingsStore)
  23. const { toggleDevice, foldSideBar, openSideBar, updateTheme } = settingsStore
  24. const mobile = ref(false)
  25. let oldLayout = theme.value.layout
  26. const imports = import.meta.glob<ComponentType>('./**/*.vue', { eager: true })
  27. const Components: Record<string, Component> = {}
  28. Object.getOwnPropertyNames(imports).forEach((key: any) => {
  29. Components[key.replace(/(\/|\.|index.vue)/g, '')] = imports[key].default
  30. })
  31. const layout = computed(() => {
  32. return Components[convertToCamelCase(`vab-layout-${theme.value.layout}`)]
  33. })
  34. const resizeBody = () => {
  35. mobile.value = document.body.getBoundingClientRect().width - 1 < 992
  36. }
  37. watch(mobile, (value) => {
  38. if (value) {
  39. oldLayout = theme.value.layout
  40. foldSideBar()
  41. } else openSideBar()
  42. theme.value.layout = value ? 'vertical' : oldLayout
  43. toggleDevice(value ? 'mobile' : 'desktop')
  44. })
  45. onBeforeMount(() => {
  46. resizeBody()
  47. window.addEventListener('resize', resizeBody)
  48. updateTheme()
  49. })
  50. onBeforeUnmount(() => {
  51. if (mobile) theme.value.layout = oldLayout
  52. window.removeEventListener('resize', resizeBody)
  53. })
  54. </script>
  55. <style lang="scss" scoped>
  56. .el-scrollbar__view.scroll-view {
  57. overflow: auto;
  58. }
  59. .vue-shop-vite-box {
  60. position: relative;
  61. width: 100%;
  62. height: 100%;
  63. [class*='vab-layout-'] {
  64. :deep() {
  65. .vab-layout-header {
  66. border-bottom: 1px solid var(--el-border-color);
  67. &.is-no-tabs {
  68. border-bottom: 0;
  69. }
  70. }
  71. }
  72. &.fixed {
  73. padding-top: calc(var(--el-nav-height) + var(--el-tabs-height));
  74. }
  75. &.fixed.no-tabs-bar {
  76. padding-top: var(--el-nav-height);
  77. }
  78. }
  79. :deep() {
  80. .fixed-header {
  81. position: fixed;
  82. top: 0;
  83. right: 0;
  84. z-index: calc(var(--el-z-index) - 1);
  85. width: 100%;
  86. }
  87. .vab-main {
  88. position: relative;
  89. width: auto;
  90. min-height: 100%;
  91. margin-left: var(--el-left-menu-width);
  92. &.is-collapse-main {
  93. margin-left: var(--el-left-menu-width-min);
  94. .fixed-header {
  95. width: var(--el-right-content-width-min);
  96. }
  97. }
  98. &:not(.is-collapse-main) {
  99. .fixed-header {
  100. width: calc(100% - var(--el-left-menu-width));
  101. }
  102. }
  103. }
  104. }
  105. /* 手机端开始 */
  106. &.mobile {
  107. :deep() {
  108. .vab-layout-vertical {
  109. .el-scrollbar.vab-side-bar.is-collapse {
  110. width: 0;
  111. }
  112. .vab-main {
  113. .fixed-header {
  114. width: 100%;
  115. }
  116. margin-left: 0;
  117. }
  118. }
  119. /* 隐藏分页和页码跳转 */
  120. .el-pager,
  121. .el-pagination__jump {
  122. display: none;
  123. }
  124. }
  125. }
  126. /* 手机端结束 */
  127. }
  128. </style>