ソースを参照

feat[sidebar]: add resonsive sidebar

Pan 7 年 前
コミット
c3ee00472d
共有5 個のファイルを変更した113 個の追加14 個の削除を含む
  1. 1 0
      src/store/getters.js
  2. 18 2
      src/store/modules/app.js
  3. 32 3
      src/styles/sidebar.scss
  4. 21 9
      src/views/layout/Layout.vue
  5. 41 0
      src/views/layout/mixin/ResizeHandler.js

+ 1 - 0
src/store/getters.js

@@ -1,5 +1,6 @@
1 1
 const getters = {
2 2
   sidebar: state => state.app.sidebar,
3
+  device: state => state.app.device,
3 4
   token: state => state.user.token,
4 5
   avatar: state => state.user.avatar,
5 6
   name: state => state.user.name,

+ 18 - 2
src/store/modules/app.js

@@ -3,8 +3,10 @@ import Cookies from 'js-cookie'
3 3
 const app = {
4 4
   state: {
5 5
     sidebar: {
6
-      opened: !+Cookies.get('sidebarStatus')
7
-    }
6
+      opened: !+Cookies.get('sidebarStatus'),
7
+      withoutAnimation: false
8
+    },
9
+    device: 'desktop'
8 10
   },
9 11
   mutations: {
10 12
     TOGGLE_SIDEBAR: state => {
@@ -14,11 +16,25 @@ const app = {
14 16
         Cookies.set('sidebarStatus', 0)
15 17
       }
16 18
       state.sidebar.opened = !state.sidebar.opened
19
+    },
20
+    CLOSE_SIDEBAR: (state, withoutAnimation) => {
21
+      Cookies.set('sidebarStatus', 1)
22
+      state.sidebar.opened = false
23
+      state.sidebar.withoutAnimation = withoutAnimation
24
+    },
25
+    TOGGLE_DEVICE: (state, device) => {
26
+      state.device = device
17 27
     }
18 28
   },
19 29
   actions: {
20 30
     ToggleSideBar: ({ commit }) => {
21 31
       commit('TOGGLE_SIDEBAR')
32
+    },
33
+    CloseSideBar({ commit }, { withoutAnimation }) {
34
+      commit('CLOSE_SIDEBAR', withoutAnimation)
35
+    },
36
+    ToggleDevice({ commit }, device) {
37
+      commit('TOGGLE_DEVICE', device)
22 38
     }
23 39
   }
24 40
 }

+ 32 - 3
src/styles/sidebar.scss

@@ -1,11 +1,13 @@
1 1
 #app {
2
+
2 3
   // 主体区域
3 4
   .main-container {
4 5
     min-height: 100%;
5 6
     transition: margin-left .28s;
6 7
     margin-left: 180px;
7 8
   }
8
-  // 侧边栏
9
+
10
+   // 侧边栏
9 11
   .sidebar-container {
10 12
     .horizontal-collapse-transition {
11 13
       transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
@@ -32,6 +34,7 @@
32 34
       width: 100% !important;
33 35
     }
34 36
   }
37
+
35 38
   .hideSidebar {
36 39
     .sidebar-container {
37 40
       width: 36px !important;
@@ -62,8 +65,9 @@
62 65
       }
63 66
     }
64 67
   }
65
-  .nest-menu .el-submenu>.el-submenu__title,
66
-  .el-submenu .el-menu-item {
68
+
69
+  .sidebar-container .nest-menu .el-submenu>.el-submenu__title,
70
+  .sidebar-container .el-submenu .el-menu-item {
67 71
     min-width: 180px !important;
68 72
     background-color: $subMenuBg !important;
69 73
     &:hover {
@@ -73,4 +77,29 @@
73 77
   .el-menu--collapse .el-menu .el-submenu {
74 78
     min-width: 180px !important;
75 79
   }
80
+
81
+  //适配移动端
82
+  .mobile {
83
+    .main-container {
84
+      margin-left: 0px;
85
+    }
86
+    .sidebar-container {
87
+      top: 50px;
88
+      transition: transform .28s;
89
+      width: 180px !important;
90
+    }
91
+    &.hideSidebar {
92
+      .sidebar-container {
93
+        transition-duration: 0.3s;
94
+        transform: translate3d(-180px, 0, 0);
95
+      }
96
+    }
97
+  }
98
+
99
+  .withoutAnimation {
100
+    .main-container,
101
+    .sidebar-container {
102
+      transition: none;
103
+    }
104
+  }
76 105
 }

+ 21 - 9
src/views/layout/Layout.vue

@@ -1,5 +1,5 @@
1 1
 <template>
2
-  <div class="app-wrapper" :class="{hideSidebar:!sidebar.opened}">
2
+  <div class="app-wrapper" :class="classObj">
3 3
     <sidebar class="sidebar-container"></sidebar>
4 4
     <div class="main-container">
5 5
       <navbar></navbar>
@@ -9,7 +9,8 @@
9 9
 </template>
10 10
 
11 11
 <script>
12
-import { Navbar, Sidebar, AppMain } from '@/views/layout/components'
12
+import { Navbar, Sidebar, AppMain } from './components'
13
+import ResizeMixin from './mixin/ResizeHandler'
13 14
 
14 15
 export default {
15 16
   name: 'layout',
@@ -18,20 +19,31 @@ export default {
18 19
     Sidebar,
19 20
     AppMain
20 21
   },
22
+  mixins: [ResizeMixin],
21 23
   computed: {
22 24
     sidebar() {
23 25
       return this.$store.state.app.sidebar
26
+    },
27
+    device() {
28
+      return this.$store.state.app.device
29
+    },
30
+    classObj() {
31
+      return {
32
+        hideSidebar: !this.sidebar.opened,
33
+        withoutAnimation: this.sidebar.withoutAnimation,
34
+        mobile: this.device === 'mobile'
35
+      }
24 36
     }
25 37
   }
26 38
 }
27 39
 </script>
28 40
 
29 41
 <style rel="stylesheet/scss" lang="scss" scoped>
30
-@import "src/styles/mixin.scss";
31
-.app-wrapper {
32
-  @include clearfix;
33
-  position: relative;
34
-  height: 100%;
35
-  width: 100%;
36
-}
42
+  @import "src/styles/mixin.scss";
43
+  .app-wrapper {
44
+    @include clearfix;
45
+    position: relative;
46
+    height: 100%;
47
+    width: 100%;
48
+  }
37 49
 </style>

+ 41 - 0
src/views/layout/mixin/ResizeHandler.js

@@ -0,0 +1,41 @@
1
+import store from '@/store'
2
+
3
+const { body } = document
4
+const WIDTH = 1024
5
+const RATIO = 3
6
+
7
+export default {
8
+  watch: {
9
+    $route(route) {
10
+      if (this.device === 'mobile' && this.sidebar.opened) {
11
+        store.dispatch('CloseSideBar', { withoutAnimation: false })
12
+      }
13
+    }
14
+  },
15
+  beforeMount() {
16
+    window.addEventListener('resize', this.resizeHandler)
17
+  },
18
+  mounted() {
19
+    const isMobile = this.isMobile()
20
+    if (isMobile) {
21
+      store.dispatch('ToggleDevice', 'mobile')
22
+      store.dispatch('CloseSideBar', { withoutAnimation: true })
23
+    }
24
+  },
25
+  methods: {
26
+    isMobile() {
27
+      const rect = body.getBoundingClientRect()
28
+      return rect.width - RATIO < WIDTH
29
+    },
30
+    resizeHandler() {
31
+      if (!document.hidden) {
32
+        const isMobile = this.isMobile()
33
+        store.dispatch('ToggleDevice', isMobile ? 'mobile' : 'desktop')
34
+
35
+        if (isMobile) {
36
+          store.dispatch('CloseSideBar', { withoutAnimation: true })
37
+        }
38
+      }
39
+    }
40
+  }
41
+}