后台侧边菜单栏伸缩功能的实现

1,067 阅读1分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

后台管理系统中,通常会实现侧边菜单栏侧边栏伸缩的功能,本文记录该效果使用vue3如何实现。

效果图如下

伸缩功能1.png

伸缩2.png

布局结构

<template>
  <div
    class="app-wrapper"
  >
    <!-- 左侧 menu -->
    <sidebar
      id="guide-sidebar"
      class="sidebar-container"
      :style="{ backgroundColor: variables.menuBg }"
    />
    <div class="main-container">
      <div class="fixed-header">
        <!-- 顶部的 navbar -->
        <navbar />
      </div>
      <!-- 内容区 -->
      <app-main />
    </div>
  </div>
</template>

首先定义数据,用于定义菜单栏是否折叠,因为该数据在菜单栏和头部都需要使用,将其定义到vuex中,新建一个模块app.js,同时定义一个将其取反的方法,添加到vuex中

//app.js
export default {
  namespaced: true,
  state: () => ({
    sidebarOpened: true
  }),
  mutations: {
    triggerSidebarOpened(state) {
      state.sidebarOpened = !state.sidebarOpened
    }
  }
}
import { createStore } from 'vuex'
import user from './modules/user'
import app from './modules/app'
import getters from './getters'

export default createStore({
  getters,
  modules: {
    user,
    app
  }
})

在头部,先实现点击切换图标的一些逻辑,将点击的图片封装为一个组件。其中实现两个功能

  1. 点击更改vuex中sidebarOpened的值,将其取反
  2. 点击后更换图片,使用计算属性,当vuex中sidebarOpened的值发生变化后,取不同的图标icon值
<template>
  <div class="hamburger-container" @click="toggleClick">
    <svg-icon class="hamburger" :icon="icon"></svg-icon>
  </div>
</template>

<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()
//取反
const toggleClick = () => {
  store.commit('app/triggerSidebarOpened')
}
//切换图片
const icon = computed(() =>
  store.getters.sidebarOpened ? 'hamburger-opened' : 'hamburger-closed'
)
</script>

<style lang="scss" scoped>
.hamburger-container {
  padding: 0 16px;
  .hamburger {
    display: inline-block;
    vertical-align: middle;
    width: 20px;
    height: 20px;
  }
}
</style>

接下来要实现菜单栏的伸缩,加上过渡,当点击伸缩时,将菜单栏的宽度变小,将右侧的宽度变大即可

<template>
  <div
    class="app-wrapper"
    <!-- 动态添加类名 -->
    :class="[$store.getters.sidebarOpened ? 'openSidebar' : 'hideSidebar']"
  >
    <!-- 左侧 menu -->
    <sidebar
      id="guide-sidebar"
      class="sidebar-container"
      :style="{ backgroundColor: variables.menuBg }"
    />
    <div class="main-container">
      <div class="fixed-header">
        <!-- 顶部的 navbar -->
        <navbar />
      </div>
      <!-- 内容区 -->
      <app-main />
    </div>
  </div>
</template>

加过渡效果

@import '~@/styles/variables.module.scss';
// 头部
.fixed-header {
  width: calc(100% - #{$sideBarWidth});
  transition: width #{$sidebarDuration};
}
.hideSidebar .fixed-header {
  width: calc(100% - #{$hideSideBarWidth});
}
// 内容区
.main-container {
    transition: margin-left #{$sidebarDuration};
    margin-left: $sideBarWidth;
}
// 左侧menu
.sidebar-container {
    //sidebarDuration为折叠后长度
    transition: width #{$sidebarDuration};
    //sideBarWidth为未折叠长度
    width: $sideBarWidth !important;
}

补充一下sass文件

// variables.module.scss
// sidebar
$menuText: #bfcbd9;
$menuActiveText: #ffffff;
$subMenuActiveText: #f4f4f5;

$menuBg: #304156;
$menuHover: #263445;

$subMenuBg: #1f2d3d;
$subMenuHover: #001528;

$sideBarWidth: 210px;
$hideSideBarWidth: 54px;
$sidebarDuration: 0.28s;
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
// JS 与 scss 共享变量,在 scss 中通过 :export 进行导出,在 js 中可通过 ESM 进行导入
:export {
  menuText: $menuText;
  menuActiveText: $menuActiveText;
  subMenuActiveText: $subMenuActiveText;
  menuBg: $menuBg;
  menuHover: $menuHover;
  subMenuBg: $subMenuBg;
  subMenuHover: $subMenuHover;
  sideBarWidth: $sideBarWidth;
}