侧边栏伸缩
This commit is contained in:
parent
d59f99da21
commit
a5506ddcd6
|
|
@ -19,15 +19,11 @@ declare module 'vue' {
|
|||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
|
|
|
|||
|
|
@ -2,17 +2,24 @@
|
|||
<div class="layout-container">
|
||||
<el-container>
|
||||
<!-- 侧边栏 -->
|
||||
<el-aside :width="sidebarWidth">
|
||||
<el-aside :width="sidebarWidth" v-show="!isHidden" :class="['sidebar-container', { resizing: isResizing }]">
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<h3>Admin System</h3>
|
||||
<template v-if="autoCollapse">
|
||||
<el-icon size="24" style="color: white;">
|
||||
<Setting />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template v-else>
|
||||
<h3>Admin System</h3>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
class="sidebar-menu"
|
||||
router
|
||||
:collapse="isCollapse"
|
||||
:collapse="autoCollapse"
|
||||
background-color="#304156"
|
||||
text-color="#bfcbd9"
|
||||
active-text-color="#409eff"
|
||||
|
|
@ -41,6 +48,14 @@
|
|||
</div>
|
||||
</el-menu>
|
||||
</div>
|
||||
|
||||
<!-- 拖拽调整手柄 -->
|
||||
<div class="resize-handle" @mousedown="startResize"></div>
|
||||
|
||||
<!-- 拖拽时的宽度提示 -->
|
||||
<div v-if="isResizing" class="resize-tooltip">
|
||||
{{ sidebarWidthValue }}px
|
||||
</div>
|
||||
</el-aside>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
|
|
@ -50,10 +65,19 @@
|
|||
<div class="header-left">
|
||||
<el-button
|
||||
type="text"
|
||||
class="sidebar-toggle-btn"
|
||||
@click="toggleSidebar"
|
||||
>
|
||||
<el-icon size="20">
|
||||
<component :is="isCollapse ? 'Expand' : 'Fold'" />
|
||||
<template v-if="isHidden">
|
||||
<Menu />
|
||||
</template>
|
||||
<template v-else-if="autoCollapse">
|
||||
<Expand />
|
||||
</template>
|
||||
<template v-else>
|
||||
<Fold />
|
||||
</template>
|
||||
</el-icon>
|
||||
</el-button>
|
||||
|
||||
|
|
@ -122,9 +146,13 @@ import { useTabsStore } from '@/stores/tabs'
|
|||
import { useUserStore } from '@/stores/user'
|
||||
import {
|
||||
ArrowDown,
|
||||
Expand,
|
||||
Fold,
|
||||
House,
|
||||
Loading,
|
||||
Lock,
|
||||
Menu,
|
||||
Setting,
|
||||
SwitchButton,
|
||||
User
|
||||
} from '@element-plus/icons-vue'
|
||||
|
|
@ -149,9 +177,25 @@ const cachedViews = computed(() => {
|
|||
|
||||
// 侧边栏状态
|
||||
const isCollapse = ref(false)
|
||||
const isHidden = ref(false)
|
||||
const sidebarWidthValue = ref(200) // 实际宽度值
|
||||
const isResizing = ref(false)
|
||||
|
||||
// 最小和最大宽度
|
||||
const MIN_WIDTH = 64
|
||||
const MAX_WIDTH = 400
|
||||
const COLLAPSE_THRESHOLD = 120 // 小于此宽度自动折叠
|
||||
|
||||
// 侧边栏宽度
|
||||
const sidebarWidth = computed(() => isCollapse.value ? '64px' : '200px')
|
||||
const sidebarWidth = computed(() => {
|
||||
if (isHidden.value) return '0px'
|
||||
return `${sidebarWidthValue.value}px`
|
||||
})
|
||||
|
||||
// 根据宽度自动判断是否折叠
|
||||
const autoCollapse = computed(() => {
|
||||
return sidebarWidthValue.value < COLLAPSE_THRESHOLD
|
||||
})
|
||||
|
||||
// 当前激活的菜单
|
||||
const activeMenu = computed(() => route.path)
|
||||
|
|
@ -164,9 +208,52 @@ const breadcrumbs = computed(() => {
|
|||
|
||||
// 切换侧边栏
|
||||
const toggleSidebar = () => {
|
||||
isCollapse.value = !isCollapse.value
|
||||
if (!isHidden.value && !autoCollapse.value) {
|
||||
// 展开 → 折叠
|
||||
sidebarWidthValue.value = MIN_WIDTH
|
||||
} else if (!isHidden.value && autoCollapse.value) {
|
||||
// 折叠 → 隐藏
|
||||
isHidden.value = true
|
||||
} else {
|
||||
// 隐藏 → 展开
|
||||
isHidden.value = false
|
||||
sidebarWidthValue.value = 200
|
||||
}
|
||||
}
|
||||
|
||||
// 拖拽调整宽度
|
||||
const startResize = (e: MouseEvent) => {
|
||||
isResizing.value = true
|
||||
document.addEventListener('mousemove', handleResize)
|
||||
document.addEventListener('mouseup', stopResize)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
const handleResize = (e: MouseEvent) => {
|
||||
if (!isResizing.value) return
|
||||
|
||||
const newWidth = e.clientX
|
||||
if (newWidth >= MIN_WIDTH && newWidth <= MAX_WIDTH) {
|
||||
sidebarWidthValue.value = newWidth
|
||||
}
|
||||
}
|
||||
|
||||
const stopResize = () => {
|
||||
isResizing.value = false
|
||||
document.removeEventListener('mousemove', handleResize)
|
||||
document.removeEventListener('mouseup', stopResize)
|
||||
|
||||
// 拖拽结束时,如果宽度接近边界值,自动调整到边界
|
||||
if (sidebarWidthValue.value < MIN_WIDTH + 10) {
|
||||
sidebarWidthValue.value = MIN_WIDTH
|
||||
}
|
||||
}
|
||||
|
||||
// 监听宽度变化,保存到localStorage
|
||||
watch(sidebarWidthValue, (newWidth) => {
|
||||
localStorage.setItem('sidebarWidth', newWidth.toString())
|
||||
})
|
||||
|
||||
// 处理个人信息
|
||||
const handleProfile = () => {
|
||||
ElMessageBox.alert('个人信息功能待开发', '提示', {
|
||||
|
|
@ -196,8 +283,17 @@ const handleLogout = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// 组件挂载时加载菜单
|
||||
// 组件挂载时加载菜单和恢复宽度
|
||||
onMounted(async () => {
|
||||
// 恢复侧边栏宽度
|
||||
const savedWidth = localStorage.getItem('sidebarWidth')
|
||||
if (savedWidth) {
|
||||
const width = parseInt(savedWidth)
|
||||
if (width >= MIN_WIDTH && width <= MAX_WIDTH) {
|
||||
sidebarWidthValue.value = width
|
||||
}
|
||||
}
|
||||
|
||||
// 只有在用户已登录但菜单未加载时才加载菜单
|
||||
if (userStore.token && !menuStore.isMenuLoaded) {
|
||||
try {
|
||||
|
|
@ -226,9 +322,60 @@ watch(
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
position: relative;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-container:not(.resizing) {
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-container.resizing {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
height: 100vh;
|
||||
background-color: #304156;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 拖拽手柄样式 */
|
||||
.resize-handle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -2px;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
cursor: col-resize;
|
||||
z-index: 10;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.resize-handle:hover {
|
||||
background-color: #409eff;
|
||||
}
|
||||
|
||||
.resize-handle:active {
|
||||
background-color: #337ecc;
|
||||
}
|
||||
|
||||
/* 拖拽提示样式 */
|
||||
.resize-tooltip {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
|
@ -239,12 +386,16 @@ watch(
|
|||
background-color: #2c3e50;
|
||||
color: white;
|
||||
margin-bottom: 0;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.logo h3 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
|
|
@ -268,6 +419,17 @@ watch(
|
|||
gap: 20px;
|
||||
}
|
||||
|
||||
.sidebar-toggle-btn {
|
||||
color: #606266 !important;
|
||||
padding: 8px !important;
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
|
||||
.sidebar-toggle-btn:hover {
|
||||
background-color: #f5f7fa !important;
|
||||
color: #409eff !important;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
Loading…
Reference in New Issue