Browse Source

feat: 🎸 重构layout-classic布局

chenkl 4 years ago
parent
commit
29d9c98860

+ 1 - 1
package.json

@@ -1,5 +1,5 @@
 {
-  "name": "vue-antdv-admin-webpack",
+  "name": "vue-element-admin-webpack",
   "version": "0.1.0",
   "private": true,
   "scripts": {

+ 25 - 5
src/components/Setting/index.vue

@@ -24,10 +24,18 @@
     <div class="setting__title">顶部菜单主题</div>
 
     <div class="setting__title">界面功能</div>
-    <div class="setting__item">
+    <!-- <div class="setting__item">
       <span>固定顶部操作栏</span>
       <el-switch v-model="fixedNavbar" @change="setFixedNavbar" />
     </div>
+    <div class="setting__item">
+      <span>固定标签页</span>
+      <el-switch v-model="fixedTags" @change="setFixedTags" />
+    </div> -->
+    <div class="setting__item">
+      <span>固定Header</span>
+      <el-switch v-model="fixedHeader" @change="setFixedHeader" />
+    </div>
 
     <div class="setting__title">界面显示</div>
     <div class="setting__item">
@@ -73,9 +81,19 @@ export default defineComponent({
       appStore.SetLayout(mode)
     }
 
-    const fixedNavbar = ref<boolean>(appStore.fixedNavbar)
-    function setFixedNavbar(fixedNavbar: boolean) {
-      appStore.SetFixedNavbar(fixedNavbar)
+    // const fixedNavbar = ref<boolean>(appStore.fixedNavbar)
+    // function setFixedNavbar(fixedNavbar: boolean) {
+    //   appStore.SetFixedNavbar(fixedNavbar)
+    // }
+
+    // const fixedTags = ref<boolean>(appStore.fixedTags)
+    // function setFixedTags(fixedTags: boolean) {
+    //   appStore.SetFixedTags(fixedTags)
+    // }
+
+    const fixedHeader = ref<boolean>(appStore.fixedHeader)
+    function setFixedHeader(fixedHeader: boolean) {
+      appStore.SetFixedHeader(fixedHeader)
     }
 
     const navbar = ref<boolean>(appStore.showNavbar)
@@ -115,7 +133,9 @@ export default defineComponent({
 
     return {
       layout, setLayout,
-      fixedNavbar, setFixedNavbar,
+      // fixedNavbar, setFixedNavbar,
+      // fixedTags, setFixedTags,
+      fixedHeader, setFixedHeader,
       navbar, setNavbar,
       hamburger, setHamburger,
       breadcrumb, setBreadcrumb,

+ 5 - 4
src/components/Sider/SiderItem.vue

@@ -1,7 +1,7 @@
 <template>
-  <template v-if="!item.meta?.hidden">
+  <div v-if="!item.meta?.hidden">
     <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.meta?.alwaysShow">
-      <el-menu-item :index="resolvePath(onlyOneChild.path)">
+      <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown': !isNest}">
         <item v-if="onlyOneChild.meta" :icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
         <template #title>
           <span class="anticon-item">{{ onlyOneChild.meta.title }}</span>
@@ -9,7 +9,7 @@
       </el-menu-item>
     </template>
 
-    <el-submenu v-else :index="resolvePath(item.path)">
+    <el-submenu v-else popper-class="nest-popper-menu" :index="resolvePath(item.path)">
       <template #title>
         <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
       </template>
@@ -19,9 +19,10 @@
         :is-nest="true"
         :item="child"
         :base-path="resolvePath(child.path)"
+        class="nest-menu"
       />
     </el-submenu>
-  </template>
+  </div>
 </template>
 
 <script lang="ts">

+ 1 - 5
src/components/Sider/index.vue

@@ -5,9 +5,6 @@
         :default-active="activeMenu"
         :collapse="collapsed"
         :unique-opened="false"
-        :background-color="variables.menuBg"
-        :text-color="variables.menuText"
-        :active-text-color="variables.menuActiveText"
         mode="vertical"
         @select="selectMenu"
       >
@@ -73,7 +70,6 @@ export default defineComponent({
 <style lang="less" scoped>
 .sidebar-container {
   height: 100%;
-  background: @menuBg;
   @{deep}(.svg-icon) {
     margin-right: 16px;
   }
@@ -88,7 +84,7 @@ export default defineComponent({
     overflow: scroll;
     overflow-x: hidden;
     .el-menu {
-      width: 100% !important;
+      width: 100%;
       border: none;
     }
   }

+ 6 - 6
src/pages/index/layout/index.vue

@@ -5,18 +5,18 @@
 </template>
 
 <script lang="ts">
-import Classic from './modules/Classic.vue'
-import Top from './modules/Top.vue'
-import LeftTop from './modules/LeftTop.vue'
+// import Classic from './modules/Classic.vue'
+// import Top from './modules/Top.vue'
+// import LeftTop from './modules/LeftTop.vue'
 import Test from './modules/Test.vue'
 import { defineComponent, ref } from 'vue'
 import config from '_p/index/config'
 export default defineComponent({
   name: 'Layout',
   components: {
-    Classic,
-    Top,
-    LeftTop,
+    // Classic,
+    // Top,
+    // LeftTop,
     Test
   },
   setup() {

+ 95 - 70
src/pages/index/layout/modules/Test.vue

@@ -16,31 +16,40 @@
       <el-scrollbar
         class="main__wrap--content"
         :class="{
-          'main__wrap--navFixed': fixedNavbar
+          'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
+          'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
+          'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
         }"
       >
         <div
-          v-if="showNavbar"
-          class="navbar__wrap"
+          class="header__wrap"
           :class="{
-            'navbar__wrap--fixed': fixedNavbar,
-            'navbar__wrap--collapsed': fixedNavbar && collapsed
+            'header__wrap--fixed': fixedHeader,
+            'header__wrap--collapsed': fixedHeader && collapsed
           }"
         >
-          <hamburger
-            v-if="showHamburger"
-            :collapsed="collapsed"
-            class="hover-container"
-            @toggleClick="setCollapsed"
-          />
-          <breadcrumb v-if="showBreadcrumb" />
-          <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
-            <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
-            <user-info v-if="showUserInfo" class="hover-container user-container" />
+          <div
+            v-if="showNavbar"
+            class="navbar__wrap"
+          >
+            <hamburger
+              v-if="showHamburger"
+              :collapsed="collapsed"
+              class="hover-container"
+              @toggleClick="setCollapsed"
+            />
+            <breadcrumb v-if="showBreadcrumb" />
+            <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
+              <screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
+              <user-info v-if="showUserInfo" class="hover-container user-container" />
+            </div>
+          </div>
+          <div
+            v-if="showTags"
+            class="tags__wrap"
+          >
+            <tags-view />
           </div>
-        </div>
-        <div v-if="showTags" class="tags__wrap">
-          <tags-view />
         </div>
         <app-main />
       </el-scrollbar>
@@ -101,7 +110,9 @@ export default defineComponent({
     const showScreenfull = computed(() => appStore.showScreenfull)
     const showUserInfo = computed(() => appStore.showUserInfo)
     const showNavbar = computed(() => appStore.showNavbar)
-    const fixedNavbar = computed(() => appStore.fixedNavbar)
+    // const fixedNavbar = computed(() => appStore.fixedNavbar)
+    // const fixedTags = computed(() => appStore.fixedTags)
+    const fixedHeader = computed(() => appStore.fixedHeader)
 
     const classObj = computed(() => {
       const obj = {}
@@ -128,7 +139,9 @@ export default defineComponent({
       showScreenfull,
       showUserInfo,
       showNavbar,
-      fixedNavbar,
+      fixedHeader,
+      // fixedNavbar,
+      // fixedTags,
       setCollapsed,
       toggleClick
     }
@@ -137,7 +150,7 @@ export default defineComponent({
 </script>
 
 <style lang="less" scoped>
-.app__wrap--Classic {
+.app__wrap {
   position: relative;
   height: 100%;
   width: 100%;
@@ -163,58 +176,47 @@ export default defineComponent({
     left: @menuWidth;
     transition: all 0.2s;
     z-index: 1;
-    .navbar__wrap {
-      display: flex;
-      align-items: center;
-      height: @navbarHeight;
-      padding: 0 20px 0 15px;
-      position: relative;
-      background: @contentBg;
+    .header__wrap {
       transition: all 0.2s;
-      &:after {
-        content: "";
-        width: 100%;
-        height: 1px;
-        border-top: 1px solid #d8dce5;
-        position: absolute;
-        bottom: 0;
-        left: 0;
-      }
-      @{deep}(.hover-container) {
-        transition: background 0.2s;
-        height: 100%;
-        line-height: @navbarHeight + 5px;
-        padding: 0 5px;
-        &:hover {
-          background: #f6f6f6;
-        }
-      }
-      .navbar__wrap--right {
+      .navbar__wrap {
         display: flex;
         align-items: center;
         height: @navbarHeight;
-        position: absolute;
-        top: 0;
-        right: 20px;
-        @{deep}(.screenfull-container),
-        @{deep}(.user-container) {
-          line-height: @navbarHeight !important;
+        padding: 0 20px 0 15px;
+        position: relative;
+        background: @contentBg;
+        &:after {
+          content: "";
+          width: 100%;
+          height: 1px;
+          border-top: 1px solid #d8dce5;
+          position: absolute;
+          bottom: 0;
+          left: 0;
+        }
+        @{deep}(.hover-container) {
+          transition: background 0.2s;
+          height: 100%;
+          line-height: @navbarHeight + 5px;
+          padding: 0 5px;
+          &:hover {
+            background: #f6f6f6;
+          }
+        }
+        .navbar__wrap--right {
+          display: flex;
+          align-items: center;
+          height: @navbarHeight;
+          position: absolute;
+          top: 0;
+          right: 20px;
+          @{deep}(.screenfull-container),
+          @{deep}(.user-container) {
+            line-height: @navbarHeight !important;
+          }
         }
       }
     }
-    // 固定顶部操作栏
-    .navbar__wrap--fixed {
-      position: fixed;
-      width: calc(~"100% - @{menuWidth} - 35px");
-      top: 0;
-      left: @menuWidth;
-      z-index: 200;
-    }
-    .navbar__wrap--collapsed {
-      width: calc(~"100% - @{menuMinWidth} - 35px");
-      left: @menuMinWidth;
-    }
-    // 固定顶部操作栏
 
     // content样式
     .main__wrap--content {
@@ -223,10 +225,6 @@ export default defineComponent({
         overflow-x: hidden;
       }
     }
-    .main__wrap--navFixed {
-      padding-top: @navbarHeight;
-      height: calc(~"100% - @{navbarHeight}");
-    }
     // content样式
   }
   .main__wrap--collapsed {
@@ -235,6 +233,33 @@ export default defineComponent({
   }
 }
 
+// 经典模式
+.app__wrap--Classic {
+  .main__wrap--fixed--all {
+    margin-top: @navbarHeight + @tagsViewHeight !important;
+    height: calc(~"100% - @{navbarHeight} - @{tagsViewHeight}") !important;
+  }
+  .main__wrap--fixed--nav {
+    margin-top: @navbarHeight !important;
+    height: calc(~"100% - @{navbarHeight}") !important;
+  }
+  .main__wrap--fixed--tags {
+    margin-top: @tagsViewHeight !important;
+    height: calc(~"100% - @{tagsViewHeight}") !important;
+  }
+  .header__wrap--fixed {
+    position: fixed !important;
+    width: calc(~"100% - @{menuWidth}") !important;
+    top: 0 !important;
+    left: @menuWidth !important;
+    z-index: 200;
+  }
+  .header__wrap--collapsed {
+    width: calc(~"100% - @{menuMinWidth}") !important;
+    left: @menuMinWidth !important;
+  }
+}
+
 // 项目配置
 .setting__wrap {
   position: fixed;

+ 27 - 17
src/pages/index/store/modules/app.ts

@@ -6,8 +6,9 @@ export interface AppState {
   showTags: boolean
   showLogo: boolean
   showNavbar: boolean
-  fixedTags: boolean
-  fixedNavbar: boolean
+  fixedHeader: boolean
+  // fixedTags: boolean
+  // fixedNavbar: boolean
   layout: string
   showBreadcrumb: boolean
   showHamburger: boolean
@@ -21,8 +22,9 @@ class App extends VuexModule implements AppState {
   public showLogo = true // 是否显示logo
   public showTags = true // 是否显示标签栏
   public showNavbar = true // 是否显示navbar
-  public fixedTags = true // 是否固定标签栏
-  public fixedNavbar = true // 是否固定navbar
+  // public fixedTags = true // 是否固定标签栏
+  // public fixedNavbar = true // 是否固定navbar
+  public fixedHeader = true // 是否固定header
   public layout = 'Classic' // layout布局
   public showBreadcrumb = true // 是否显示面包屑
   public showHamburger = true // 是否显示侧边栏缩收按钮
@@ -45,13 +47,17 @@ class App extends VuexModule implements AppState {
   private SET_NAVBAR(showNavbar: boolean): void {
     this.showNavbar = showNavbar
   }
+  // @Mutation
+  // private SET_FIXEDTAGS(fixedTags: boolean): void {
+  //   this.fixedTags = fixedTags
+  // }
+  // @Mutation
+  // private SET_FIXEDNAVBAR(fixedNavbar: boolean): void {
+  //   this.fixedNavbar = fixedNavbar
+  // }
   @Mutation
-  private SET_FIXEDTAGS(fixedTags: boolean): void {
-    this.fixedTags = fixedTags
-  }
-  @Mutation
-  private SET_FIXEDNAVBAR(fixedNavbar: boolean): void {
-    this.fixedNavbar = fixedNavbar
+  private SET_FIXEDHEADER(fixedHeader: boolean): void {
+    this.fixedHeader = fixedHeader
   }
   @Mutation
   private SET_LAYOUT(layout: 'Classic' | 'LeftTop' | 'Top' | 'Test'): void {
@@ -91,13 +97,17 @@ class App extends VuexModule implements AppState {
     this.SET_NAVBAR(showNavbar)
   }
   @Action
-  public SetFixedTags(fixedTags: boolean): void {
-    this.SET_FIXEDTAGS(fixedTags)
-  }
-  @Action
-  public SetFixedNavbar(fixedNavbar: boolean): void {
-    this.SET_FIXEDNAVBAR(fixedNavbar)
-  }
+  public SetFixedHeader(fixedHeader: boolean): void {
+    this.SET_FIXEDHEADER(fixedHeader)
+  }
+  // @Action
+  // public SetFixedTags(fixedTags: boolean): void {
+  //   this.SET_FIXEDTAGS(fixedTags)
+  // }
+  // @Action
+  // public SetFixedNavbar(fixedNavbar: boolean): void {
+  //   this.SET_FIXEDNAVBAR(fixedNavbar)
+  // }
   @Action
   public SetLayout(layout: 'Classic' | 'LeftTop' | 'Top' | 'Test'): void {
     this.SET_LAYOUT(layout)

+ 1 - 1
src/styles/index.less

@@ -1,7 +1,7 @@
 @import '~element-plus/lib/theme-chalk/index.css';
 // @import './sidebar.less';
 @import './transition.less';
-@import './silder.less';
+@import './sider.less';
 @import './glob.less';
 // @import  './button.less';
 // @import  './antdv.less';

+ 108 - 0
src/styles/sider.less

@@ -0,0 +1,108 @@
+.app__wrap--Classic {
+  .horizontal-collapse-transition {
+    transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
+  }
+  .sidebar-container {
+    background: @menuBg;
+    .el-menu {
+      background-color: @menuBg !important;
+      .el-menu-item,
+      .el-submenu__title {
+        color: @menuText !important;
+        background-color: @menuBg !important;
+        i {
+          color: @menuText !important;
+        }
+      }
+      
+      .is-active {
+        color: @menuActiveText !important;
+        background-color: @subMenuHover !important;
+        &>.el-submenu__title {
+          color: @menuActiveText !important;
+        }
+      }
+      .is-opened {
+        .el-menu-item {
+          background-color: @subMenuBg !important;
+        }
+      }
+      
+      .nest-menu {
+        background-color: @subMenuBg !important;
+        .el-submenu>.el-submenu__title {
+          background-color: @subMenuBg !important;
+        }
+        .is-active {
+          background-color: @subMenuHover !important;
+        }
+      }
+      // menu hover
+      .submenu-title-noDropdown,
+      .el-submenu__title {
+        &:hover {
+          background-color: @menuBg !important;
+          color: @subMenuActiveText !important;
+        }
+      }
+      .el-menu-item:hover {
+        color: @subMenuActiveText !important;
+        background-color: @subMenuHover !important;
+      }
+    }
+    .el-menu--collapse {
+      &>div>.el-submenu {
+        i {
+          display: none;
+        }
+      }
+      .is-active {
+        &>.el-submenu__title {
+          background-color: @subMenuHover !important;
+        }
+      }
+    }
+  }
+}
+
+.nest-popper-menu {
+  background: @menuBg;
+  .el-menu {
+    background-color: @menuBg !important;
+      
+    .el-menu-item,
+    .el-submenu__title {
+      color: @menuText !important;
+      background-color: @menuBg !important;
+      i {
+        color: @menuText !important;
+      }
+    }
+      
+    .is-active {
+      color: @menuActiveText !important;
+      background-color: @subMenuHover !important;
+      &>.el-submenu__title {
+        color: @menuActiveText !important;
+      }
+    }
+      
+    .nest-menu {
+      .is-active {
+        background-color: @subMenuHover !important;
+      }
+    }
+    // menu hover
+    .submenu-title-noDropdown,
+    .el-submenu__title {
+      &:hover {
+        background-color: @menuBg !important;
+        color: @subMenuActiveText !important;
+      }
+    }
+    .el-menu-item:hover {
+      color: @subMenuActiveText !important;
+      background-color: @subMenuHover !important;
+    }
+  }
+}

+ 0 - 27
src/styles/silder.less

@@ -1,27 +0,0 @@
-.ant-layout-sider-collapsed,
-.ant-menu-horizontal {
-  .dark-active-item {
-    background: @menuDarkActiveBg;
-    .ant-menu-submenu-title {
-      color: @menuDarkActiveText;
-    }
-  }
-  .light-active-item {
-    background: @menuLightActiveBg;
-    .ant-menu-submenu-title {
-      color: @menuLightActiveText;
-    }
-  }
-}
-
-.dark-popup-active-item {
-  .ant-menu-submenu-title {
-    color: @menuDarkActiveText;
-  }
-}
-
-.light-popup-active-item {
-  .ant-menu-submenu-title {
-    color: @menuLightActiveText;
-  }
-}

+ 2 - 10
src/styles/variables.less

@@ -1,25 +1,17 @@
 // Silder
 @menuText: #bfcbd9;
-@menuActiveText: #409EFF;
+@menuActiveText: #fff;
 @menuActiveBg: #2d8cf0;
 
 @menuBg: #001529;
 
 @subMenuBg: #1f2d3d;
-@subMenuHover: #1f2d3d;
+@subMenuHover: #2d8cf0;
 @subMenuActiveText: #fff;
 
 @menuWidth: 200px;
 @menuMinWidth: 64px;
 
-@menuLightActiveText: #1890ff;
-@menuLightActiveBg: #e6f7ff;
-
-@menuDarkActiveText: #fff;
-@menuDarkActiveBg: #1890ff;
-
-@menuLightBg: #fff;
-
 // topSilder
 @topSilderHeight: 50px;