本文正在参加「金石计划 . 瓜分6万现金大奖」
后台管理系统中,通常会实现侧边菜单栏侧边栏伸缩的功能,本文记录该效果使用vue3如何实现。
效果图如下
布局结构
<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
}
})
在头部,先实现点击切换图标的一些逻辑,将点击的图片封装为一个组件。其中实现两个功能
- 点击更改vuex中sidebarOpened的值,将其取反
- 点击后更换图片,使用计算属性,当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;
}