index.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <div :class="classes" class="app-wrapper">
  3. <div
  4. v-if="device === 'mobile' && sidebar.opened"
  5. class="drawer-bg"
  6. @click="handleClickOutside"
  7. />
  8. <!-- 侧边栏 -->
  9. <sidebar class="sidebar-container" />
  10. <div class="main-container">
  11. <div :class="{ 'fixed-header': fixedHeader }">
  12. <!-- 顶部导航栏 -->
  13. <navbar />
  14. </div>
  15. <!-- 主体内容 -->
  16. <app-main />
  17. </div>
  18. <!-- 系统设置 -->
  19. <setting />
  20. </div>
  21. </template>
  22. <script lang="ts">
  23. import { Navbar, Sidebar, AppMain, setting } from "./components";
  24. import {
  25. ref,
  26. reactive,
  27. computed,
  28. toRefs,
  29. watch,
  30. watchEffect,
  31. onMounted,
  32. onBeforeMount,
  33. onBeforeUnmount,
  34. } from "vue";
  35. import { useStore } from "vuex";
  36. interface setInter {
  37. sidebar: any;
  38. device: String;
  39. fixedHeader: Boolean;
  40. classes: any;
  41. }
  42. export default {
  43. name: "layout",
  44. components: {
  45. Navbar,
  46. Sidebar,
  47. AppMain,
  48. setting,
  49. },
  50. setup() {
  51. const store = useStore();
  52. const WIDTH = ref(992);
  53. const set: setInter = reactive({
  54. sidebar: computed(() => {
  55. return store.state.app.sidebar;
  56. }),
  57. device: computed(() => {
  58. return store.state.app.device;
  59. }),
  60. fixedHeader: computed(() => {
  61. return store.state.settings.fixedHeader;
  62. }),
  63. classes: computed(() => {
  64. return {
  65. hideSidebar: !set.sidebar.opened,
  66. openSidebar: set.sidebar.opened,
  67. withoutAnimation: set.sidebar.withoutAnimation,
  68. mobile: set.device === "mobile",
  69. };
  70. }),
  71. });
  72. watchEffect(() => {
  73. if (set.device === "mobile" && !set.sidebar.opened) {
  74. store.dispatch("app/closeSideBar", { withoutAnimation: false });
  75. }
  76. })
  77. const handleClickOutside = () => {
  78. store.dispatch("app/closeSideBar", { withoutAnimation: false });
  79. };
  80. const $_isMobile = () => {
  81. const rect = document.body.getBoundingClientRect();
  82. return rect.width - 1 < WIDTH.value;
  83. };
  84. const $_resizeHandler = () => {
  85. if (!document.hidden) {
  86. const isMobile = $_isMobile();
  87. store.dispatch("app/toggleDevice", isMobile ? "mobile" : "desktop");
  88. if (isMobile) {
  89. store.dispatch("app/closeSideBar", { withoutAnimation: true });
  90. }
  91. }
  92. };
  93. onMounted(() => {
  94. const isMobile = $_isMobile();
  95. if (isMobile) {
  96. store.dispatch("app/toggleDevice", "mobile");
  97. store.dispatch("app/closeSideBar", { withoutAnimation: true });
  98. }
  99. });
  100. onBeforeMount(() => {
  101. window.addEventListener("resize", $_resizeHandler);
  102. });
  103. onBeforeUnmount(() => {
  104. window.removeEventListener("resize", $_resizeHandler);
  105. });
  106. return {
  107. ...toRefs(set),
  108. handleClickOutside,
  109. };
  110. },
  111. };
  112. </script>
  113. <style lang="scss" scoped>
  114. @mixin clearfix {
  115. &:after {
  116. content: "";
  117. display: table;
  118. clear: both;
  119. }
  120. }
  121. $sideBarWidth: 210px;
  122. .app-wrapper {
  123. @include clearfix;
  124. position: relative;
  125. height: 100%;
  126. width: 100%;
  127. &.mobile.openSidebar {
  128. position: fixed;
  129. top: 0;
  130. }
  131. }
  132. .drawer-bg {
  133. background: #000;
  134. opacity: 0.3;
  135. width: 100%;
  136. top: 0;
  137. height: 100%;
  138. position: absolute;
  139. z-index: 999;
  140. }
  141. .fixed-header {
  142. position: fixed;
  143. top: 0;
  144. right: 0;
  145. z-index: 9;
  146. width: calc(100% - #{$sideBarWidth});
  147. transition: width 0.28s;
  148. }
  149. .hideSidebar .fixed-header {
  150. width: calc(100% - 54px);
  151. }
  152. .mobile .fixed-header {
  153. width: 100%;
  154. }
  155. </style>