feat[sidebar]: add resonsive sidebar
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
const getters = {
 | 
			
		||||
  sidebar: state => state.app.sidebar,
 | 
			
		||||
  device: state => state.app.device,
 | 
			
		||||
  token: state => state.user.token,
 | 
			
		||||
  avatar: state => state.user.avatar,
 | 
			
		||||
  name: state => state.user.name,
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,10 @@ import Cookies from 'js-cookie'
 | 
			
		||||
const app = {
 | 
			
		||||
  state: {
 | 
			
		||||
    sidebar: {
 | 
			
		||||
      opened: !+Cookies.get('sidebarStatus')
 | 
			
		||||
    }
 | 
			
		||||
      opened: !+Cookies.get('sidebarStatus'),
 | 
			
		||||
      withoutAnimation: false
 | 
			
		||||
    },
 | 
			
		||||
    device: 'desktop'
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
    TOGGLE_SIDEBAR: state => {
 | 
			
		||||
@@ -14,11 +16,25 @@ const app = {
 | 
			
		||||
        Cookies.set('sidebarStatus', 0)
 | 
			
		||||
      }
 | 
			
		||||
      state.sidebar.opened = !state.sidebar.opened
 | 
			
		||||
    },
 | 
			
		||||
    CLOSE_SIDEBAR: (state, withoutAnimation) => {
 | 
			
		||||
      Cookies.set('sidebarStatus', 1)
 | 
			
		||||
      state.sidebar.opened = false
 | 
			
		||||
      state.sidebar.withoutAnimation = withoutAnimation
 | 
			
		||||
    },
 | 
			
		||||
    TOGGLE_DEVICE: (state, device) => {
 | 
			
		||||
      state.device = device
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
    ToggleSideBar: ({ commit }) => {
 | 
			
		||||
      commit('TOGGLE_SIDEBAR')
 | 
			
		||||
    },
 | 
			
		||||
    CloseSideBar({ commit }, { withoutAnimation }) {
 | 
			
		||||
      commit('CLOSE_SIDEBAR', withoutAnimation)
 | 
			
		||||
    },
 | 
			
		||||
    ToggleDevice({ commit }, device) {
 | 
			
		||||
      commit('TOGGLE_DEVICE', device)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
#app {
 | 
			
		||||
 | 
			
		||||
  // 主体区域
 | 
			
		||||
  .main-container {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    transition: margin-left .28s;
 | 
			
		||||
    margin-left: 180px;
 | 
			
		||||
  }
 | 
			
		||||
  // 侧边栏
 | 
			
		||||
 | 
			
		||||
   // 侧边栏
 | 
			
		||||
  .sidebar-container {
 | 
			
		||||
    .horizontal-collapse-transition {
 | 
			
		||||
      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
 | 
			
		||||
@@ -32,6 +34,7 @@
 | 
			
		||||
      width: 100% !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .hideSidebar {
 | 
			
		||||
    .sidebar-container {
 | 
			
		||||
      width: 36px !important;
 | 
			
		||||
@@ -62,8 +65,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .nest-menu .el-submenu>.el-submenu__title,
 | 
			
		||||
  .el-submenu .el-menu-item {
 | 
			
		||||
 | 
			
		||||
  .sidebar-container .nest-menu .el-submenu>.el-submenu__title,
 | 
			
		||||
  .sidebar-container .el-submenu .el-menu-item {
 | 
			
		||||
    min-width: 180px !important;
 | 
			
		||||
    background-color: $subMenuBg !important;
 | 
			
		||||
    &:hover {
 | 
			
		||||
@@ -73,4 +77,29 @@
 | 
			
		||||
  .el-menu--collapse .el-menu .el-submenu {
 | 
			
		||||
    min-width: 180px !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //适配移动端
 | 
			
		||||
  .mobile {
 | 
			
		||||
    .main-container {
 | 
			
		||||
      margin-left: 0px;
 | 
			
		||||
    }
 | 
			
		||||
    .sidebar-container {
 | 
			
		||||
      top: 50px;
 | 
			
		||||
      transition: transform .28s;
 | 
			
		||||
      width: 180px !important;
 | 
			
		||||
    }
 | 
			
		||||
    &.hideSidebar {
 | 
			
		||||
      .sidebar-container {
 | 
			
		||||
        transition-duration: 0.3s;
 | 
			
		||||
        transform: translate3d(-180px, 0, 0);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .withoutAnimation {
 | 
			
		||||
    .main-container,
 | 
			
		||||
    .sidebar-container {
 | 
			
		||||
      transition: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="app-wrapper" :class="{hideSidebar:!sidebar.opened}">
 | 
			
		||||
  <div class="app-wrapper" :class="classObj">
 | 
			
		||||
    <sidebar class="sidebar-container"></sidebar>
 | 
			
		||||
    <div class="main-container">
 | 
			
		||||
      <navbar></navbar>
 | 
			
		||||
@@ -9,7 +9,8 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Navbar, Sidebar, AppMain } from '@/views/layout/components'
 | 
			
		||||
import { Navbar, Sidebar, AppMain } from './components'
 | 
			
		||||
import ResizeMixin from './mixin/ResizeHandler'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'layout',
 | 
			
		||||
@@ -18,20 +19,31 @@ export default {
 | 
			
		||||
    Sidebar,
 | 
			
		||||
    AppMain
 | 
			
		||||
  },
 | 
			
		||||
  mixins: [ResizeMixin],
 | 
			
		||||
  computed: {
 | 
			
		||||
    sidebar() {
 | 
			
		||||
      return this.$store.state.app.sidebar
 | 
			
		||||
    },
 | 
			
		||||
    device() {
 | 
			
		||||
      return this.$store.state.app.device
 | 
			
		||||
    },
 | 
			
		||||
    classObj() {
 | 
			
		||||
      return {
 | 
			
		||||
        hideSidebar: !this.sidebar.opened,
 | 
			
		||||
        withoutAnimation: this.sidebar.withoutAnimation,
 | 
			
		||||
        mobile: this.device === 'mobile'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style rel="stylesheet/scss" lang="scss" scoped>
 | 
			
		||||
@import "src/styles/mixin.scss";
 | 
			
		||||
.app-wrapper {
 | 
			
		||||
  @include clearfix;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
  @import "src/styles/mixin.scss";
 | 
			
		||||
  .app-wrapper {
 | 
			
		||||
    @include clearfix;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								src/views/layout/mixin/ResizeHandler.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/views/layout/mixin/ResizeHandler.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
 | 
			
		||||
const { body } = document
 | 
			
		||||
const WIDTH = 1024
 | 
			
		||||
const RATIO = 3
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  watch: {
 | 
			
		||||
    $route(route) {
 | 
			
		||||
      if (this.device === 'mobile' && this.sidebar.opened) {
 | 
			
		||||
        store.dispatch('CloseSideBar', { withoutAnimation: false })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  beforeMount() {
 | 
			
		||||
    window.addEventListener('resize', this.resizeHandler)
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    const isMobile = this.isMobile()
 | 
			
		||||
    if (isMobile) {
 | 
			
		||||
      store.dispatch('ToggleDevice', 'mobile')
 | 
			
		||||
      store.dispatch('CloseSideBar', { withoutAnimation: true })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    isMobile() {
 | 
			
		||||
      const rect = body.getBoundingClientRect()
 | 
			
		||||
      return rect.width - RATIO < WIDTH
 | 
			
		||||
    },
 | 
			
		||||
    resizeHandler() {
 | 
			
		||||
      if (!document.hidden) {
 | 
			
		||||
        const isMobile = this.isMobile()
 | 
			
		||||
        store.dispatch('ToggleDevice', isMobile ? 'mobile' : 'desktop')
 | 
			
		||||
 | 
			
		||||
        if (isMobile) {
 | 
			
		||||
          store.dispatch('CloseSideBar', { withoutAnimation: true })
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user