index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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(false)"
  7. />
  8. <!-- 侧边栏 -->
  9. <sidebar class="sidebar-container" v-if="!containerHiddenSideBar" />
  10. <div class="main-container">
  11. <div :class="{ 'fixed-header': fixedHeader }">
  12. <!-- 顶部导航栏 -->
  13. <navbar v-show="!containerHiddenSideBar" />
  14. <!-- tabs标签页 -->
  15. <tag>
  16. <span @click="onFullScreen">
  17. <fullScreen v-if="!containerHiddenSideBar" />
  18. <exitScreen v-else />
  19. </span>
  20. </tag>
  21. </div>
  22. <!-- 主体内容 -->
  23. <app-main />
  24. </div>
  25. <!-- 系统设置 -->
  26. <setting />
  27. </div>
  28. </template>
  29. <script lang="ts">
  30. import { Navbar, Sidebar, AppMain, setting, tag } from "./components";
  31. import {
  32. ref,
  33. unref,
  34. reactive,
  35. computed,
  36. toRefs,
  37. watchEffect,
  38. onMounted,
  39. onBeforeMount,
  40. useCssModule
  41. } from "vue";
  42. import { useAppStoreHook } from "/@/store/modules/app";
  43. import { useSettingStoreHook } from "/@/store/modules/settings";
  44. import { useEventListener } from "@vueuse/core";
  45. import { toggleClass } from "/@/utils/operate";
  46. import options from "/@/settings";
  47. import fullScreen from "/@/assets/svg/full_screen.svg";
  48. import exitScreen from "/@/assets/svg/exit_screen.svg";
  49. interface setInter {
  50. sidebar: any;
  51. device: string;
  52. fixedHeader: boolean;
  53. classes: any;
  54. }
  55. export default {
  56. name: "layout",
  57. components: {
  58. Navbar,
  59. Sidebar,
  60. AppMain,
  61. setting,
  62. tag,
  63. fullScreen,
  64. exitScreen
  65. },
  66. setup() {
  67. const pureApp = useAppStoreHook();
  68. const pureSetting = useSettingStoreHook();
  69. const { hiddenMainContainer } = useCssModule();
  70. const WIDTH = ref(992);
  71. let containerHiddenSideBar = ref(options.hiddenSideBar);
  72. const set: setInter = reactive({
  73. sidebar: computed(() => {
  74. return pureApp.sidebar;
  75. }),
  76. device: computed(() => {
  77. return pureApp.device;
  78. }),
  79. fixedHeader: computed(() => {
  80. return pureSetting.fixedHeader;
  81. }),
  82. classes: computed(() => {
  83. return {
  84. hideSidebar: !set.sidebar.opened,
  85. openSidebar: set.sidebar.opened,
  86. withoutAnimation: set.sidebar.withoutAnimation,
  87. mobile: set.device === "mobile"
  88. };
  89. })
  90. });
  91. const handleClickOutside = (params: boolean) => {
  92. pureApp.closeSideBar({ withoutAnimation: params });
  93. };
  94. watchEffect(() => {
  95. if (set.device === "mobile" && !set.sidebar.opened) {
  96. handleClickOutside(false);
  97. }
  98. });
  99. const $_isMobile = () => {
  100. const rect = document.body.getBoundingClientRect();
  101. return rect.width - 1 < WIDTH.value;
  102. };
  103. const $_resizeHandler = () => {
  104. if (!document.hidden) {
  105. const isMobile = $_isMobile();
  106. pureApp.toggleDevice(isMobile ? "mobile" : "desktop");
  107. if (isMobile) {
  108. handleClickOutside(true);
  109. }
  110. }
  111. };
  112. function onFullScreen() {
  113. if (unref(containerHiddenSideBar)) {
  114. containerHiddenSideBar.value = false;
  115. toggleClass(
  116. false,
  117. hiddenMainContainer,
  118. document.querySelector(".main-container")
  119. );
  120. } else {
  121. containerHiddenSideBar.value = true;
  122. toggleClass(
  123. true,
  124. hiddenMainContainer,
  125. document.querySelector(".main-container")
  126. );
  127. }
  128. }
  129. onMounted(() => {
  130. const isMobile = $_isMobile();
  131. if (isMobile) {
  132. pureApp.toggleDevice("mobile");
  133. handleClickOutside(true);
  134. }
  135. toggleClass(
  136. unref(containerHiddenSideBar),
  137. hiddenMainContainer,
  138. document.querySelector(".main-container")
  139. );
  140. });
  141. onBeforeMount(() => {
  142. useEventListener("resize", $_resizeHandler);
  143. });
  144. return {
  145. ...toRefs(set),
  146. handleClickOutside,
  147. containerHiddenSideBar,
  148. onFullScreen
  149. };
  150. }
  151. };
  152. </script>
  153. <style scoped module>
  154. .hiddenMainContainer {
  155. margin-left: 0 !important;
  156. }
  157. </style>
  158. <style lang="scss" scoped>
  159. $sideBarWidth: 210px;
  160. @mixin clearfix {
  161. &::after {
  162. content: "";
  163. display: table;
  164. clear: both;
  165. }
  166. }
  167. .app-wrapper {
  168. @include clearfix;
  169. position: relative;
  170. height: 100%;
  171. width: 100%;
  172. &.mobile.openSidebar {
  173. position: fixed;
  174. top: 0;
  175. }
  176. }
  177. .drawer-bg {
  178. background: #000;
  179. opacity: 0.3;
  180. width: 100%;
  181. top: 0;
  182. height: 100%;
  183. position: absolute;
  184. z-index: 999;
  185. }
  186. .fixed-header {
  187. position: fixed;
  188. top: 0;
  189. right: 0;
  190. z-index: 9;
  191. width: calc(100% - #{$sideBarWidth});
  192. transition: width 0.28s;
  193. }
  194. .hideSidebar .fixed-header {
  195. width: calc(100% - 54px);
  196. }
  197. .mobile .fixed-header {
  198. width: 100%;
  199. }
  200. .re-screen {
  201. margin-top: 12px;
  202. }
  203. </style>