在开始构建ElementPlus侧边栏折叠功能前,我们需要先搭建好项目的基础结构。这里推荐使用Vue3的组合式API写法,配合ElementPlus 2.3.0+版本。我实际开发中发现,很多新手容易忽略版本兼容性问题,建议在package.json中明确指定element-plus版本。
首先创建三个核心文件:
在Home.vue中,我们需要设置基本的布局结构。ElementPlus的el-container组件非常适合做管理后台的骨架,实测下来它的响应式表现很稳定。这里有个小技巧:el-container默认是flex布局,建议给它设置min-height: 100vh,这样能确保页面始终占满全屏。
javascript复制// Home.vue基础结构
<template>
<el-container class="layout-container">
<el-aside>
<TAside />
</el-aside>
<el-container>
<el-header><THeader /></el-header>
<el-main><TMain /></el-main>
</el-container>
</el-container>
</template>
<script setup>
import { provide, ref } from 'vue'
import TAside from './TAside.vue'
import TMain from './TMain.vue'
// 关键点:提供全局折叠状态
const isCollapse = ref(false)
provide('isCollapse', isCollapse)
</script>
<style scoped>
.layout-container {
min-height: 100vh;
}
</style>
侧边栏折叠功能的核心在于el-menu组件的正确配置。根据我的踩坑经验,以下几个属性必须特别注意:
:collapse="isCollapse":绑定折叠状态:collapse-transition="false":关闭默认动画(避免闪烁问题)unique-opened:保持只有一个子菜单展开router:启用路由模式这里有个容易忽略的细节:el-menu-item中的文字必须用template包裹,否则折叠时文字不会隐藏。我在三个项目中都犯过这个错误,调试了半天才发现问题。
javascript复制// TAside.vue 关键代码
<el-menu
:default-active="$route.path"
:collapse="isCollapse"
:collapse-transition="false"
unique-opened
router
>
<el-menu-item index="/dashboard">
<el-icon><House /></el-icon>
<template #title>控制台</template>
</el-menu-item>
<!-- 其他菜单项 -->
</el-menu>
折叠状态下的样式调整是另一个重点。必须为el-menu设置两个关键样式:
我推荐这样写CSS:
css复制.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 220px;
min-height: 400px;
}
.el-menu--collapse .el-menu-item .el-icon {
margin-right: 0;
transform: translateX(2px);
}
Vue3的依赖注入系统非常适合处理这种跨组件状态共享。在Home.vue中provide折叠状态,在子组件中inject使用。这种方式比Vuex更轻量,实测在中小型项目中完全够用。
javascript复制// TMain.vue中的折叠按钮实现
<script setup>
const isCollapse = inject('isCollapse')
const toggleCollapse = () => {
isCollapse.value = !isCollapse.value
}
</script>
<template>
<div class="header">
<el-button @click="toggleCollapse">
<el-icon><Fold /></el-icon>
</el-button>
</div>
</template>
为了让折叠状态在页面刷新后保持不变,我通常会配合localStorage做持久化。这里分享一个经过优化的实现:
javascript复制// 在Home.vue中
const isCollapse = ref(
localStorage.getItem('menuCollapse') === 'true' || false
)
watch(isCollapse, (newVal) => {
localStorage.setItem('menuCollapse', newVal)
})
虽然我们关闭了ElementPlus自带的折叠动画,但可以添加更流畅的自定义过渡效果。我的方案是使用CSS transition:
css复制.el-aside {
transition: width 0.3s ease;
}
.el-menu {
transition: all 0.3s ease;
}
针对移动端,我通常会添加一个监听窗口大小的逻辑,在小屏幕下自动折叠菜单:
javascript复制// 在Home.vue中
import { onMounted, onUnmounted } from 'vue'
const checkScreenSize = () => {
isCollapse.value = window.innerWidth < 768
}
onMounted(() => {
checkScreenSize()
window.addEventListener('resize', checkScreenSize)
})
onUnmounted(() => {
window.removeEventListener('resize', checkScreenSize)
})
当菜单项很多时,折叠/展开操作可能会有卡顿。我通过以下方式优化:
javascript复制<el-aside>
<el-scrollbar>
<el-menu>
<!-- 菜单内容 -->
</el-menu>
</el-scrollbar>
</el-aside>
在实际项目中,我遇到过几个典型问题:
对于动态菜单,我的解决方案是:
javascript复制// 在TAside.vue中
const menuKey = ref(0)
const forceMenuRender = () => {
menuKey.value++
}
// 使用时
<el-menu :key="menuKey">
<!-- 动态菜单项 -->
</el-menu>
最后分享一个经过生产环境验证的完整实现。这个方案在我最近的后台项目中运行良好,支持以下特性:
javascript复制// Home.vue完整示例
<script setup>
import { provide, ref, watch, onMounted, onUnmounted } from 'vue'
import TAside from './TAside.vue'
import TMain from './TMain.vue'
const isCollapse = ref(
localStorage.getItem('menuCollapse') === 'true' || false
)
watch(isCollapse, (newVal) => {
localStorage.setItem('menuCollapse', newVal)
})
const checkScreenSize = () => {
if (window.innerWidth < 768) {
isCollapse.value = true
}
}
onMounted(() => {
checkScreenSize()
window.addEventListener('resize', checkScreenSize)
})
onUnmounted(() => {
window.removeEventListener('resize', checkScreenSize)
})
provide('isCollapse', isCollapse)
</script>
在开发这类功能时,我最大的体会是:细节决定成败。一个看似简单的折叠功能,实际上需要考虑状态管理、样式适配、性能优化等多个方面。特别是在企业级应用中,这些细节处理的好坏直接影响用户体验。