fix:将侧边栏兼容移动端
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
<template>
|
||||
<div class="admin-layout">
|
||||
<div class="admin-layout" :class="{ 'sidebar-collapsed': isCollapsed, 'mobile-open': isMobileMenuOpen }">
|
||||
<!-- 移动端遮罩层 -->
|
||||
<div class="mobile-overlay" v-if="isMobileMenuOpen" @click="closeMobileMenu"></div>
|
||||
|
||||
<!-- 侧边栏 -->
|
||||
<div class="sidebar">
|
||||
<div class="sidebar" :class="{ 'collapsed': isCollapsed }">
|
||||
<div class="logo-container">
|
||||
<img src="@/assets/logo.png" alt="Logo" class="logo-img" />
|
||||
<img src="@/assets/logo.png" alt="Logo" class="logo-img" v-show="!isCollapsed" />
|
||||
<img src="@/assets/logo.svg" alt="Logo" class="logo-img-mini" v-show="isCollapsed" />
|
||||
</div>
|
||||
<el-scrollbar class="sidebar-scrollbar">
|
||||
<el-menu
|
||||
@@ -13,11 +17,20 @@
|
||||
text-color="#34495e"
|
||||
active-text-color="#2c3e50"
|
||||
:unique-opened="true"
|
||||
:collapse="isCollapsed"
|
||||
:collapse-transition="false"
|
||||
router
|
||||
>
|
||||
<sidebar-menu-item v-for="menu in menus" :key="menu.path" :menu="menu" />
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
<!-- 收缩按钮 -->
|
||||
<div class="collapse-btn" @click="toggleCollapse">
|
||||
<el-icon :size="18">
|
||||
<Fold v-if="!isCollapsed" />
|
||||
<Expand v-else />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主区域 -->
|
||||
@@ -25,10 +38,14 @@
|
||||
<!-- 顶部导航 -->
|
||||
<div class="navbar">
|
||||
<div class="navbar-left">
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<el-button type="text" class="mobile-menu-btn" @click="toggleMobileMenu">
|
||||
<el-icon :size="22"><Menu /></el-icon>
|
||||
</el-button>
|
||||
<breadcrumb />
|
||||
</div>
|
||||
<div class="navbar-right">
|
||||
<div class="navbar-item">
|
||||
<div class="navbar-item hidden-mobile">
|
||||
<el-tooltip content="全屏" placement="bottom">
|
||||
<el-button type="text" class="header-btn" @click="toggleFullScreen">
|
||||
<el-icon :size="18"><full-screen /></el-icon>
|
||||
@@ -39,9 +56,9 @@
|
||||
<div class="navbar-item">
|
||||
<el-dropdown trigger="click">
|
||||
<div class="avatar-container">
|
||||
<el-avatar :size="32" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" />
|
||||
<span class="username">{{ userStore.userInfo.user_name }}</span>
|
||||
<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||
<el-avatar :size="32" :src="userStore.getUserAvatar() || 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'" />
|
||||
<span class="username hidden-mobile">{{ userStore.userInfo.user_name }}</span>
|
||||
<el-icon class="el-icon--right hidden-mobile"><arrow-down /></el-icon>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
@@ -81,7 +98,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import SidebarMenuItem from './SidebarMenuItem.vue'
|
||||
import Breadcrumb from './Breadcrumb.vue'
|
||||
@@ -92,7 +109,10 @@ import {
|
||||
ArrowDown,
|
||||
User,
|
||||
Key,
|
||||
SwitchButton
|
||||
SwitchButton,
|
||||
Fold,
|
||||
Expand,
|
||||
Menu
|
||||
} from '@element-plus/icons-vue'
|
||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
@@ -105,11 +125,46 @@ const router = useRouter()
|
||||
// 侧边栏菜单数据
|
||||
const menus = ref(menuConfig)
|
||||
|
||||
// 侧边栏收缩状态
|
||||
const isCollapsed = ref(false)
|
||||
|
||||
// 移动端菜单状态
|
||||
const isMobileMenuOpen = ref(false)
|
||||
|
||||
// 检测是否是移动端
|
||||
const isMobile = ref(false)
|
||||
|
||||
const checkMobile = () => {
|
||||
isMobile.value = window.innerWidth <= 768
|
||||
// 移动端默认收起侧边栏
|
||||
if (isMobile.value) {
|
||||
isCollapsed.value = false
|
||||
isMobileMenuOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前激活的菜单项
|
||||
const activeMenu = computed(() => {
|
||||
return route.path
|
||||
})
|
||||
|
||||
// 切换侧边栏收缩
|
||||
const toggleCollapse = () => {
|
||||
isCollapsed.value = !isCollapsed.value
|
||||
// 保存状态到localStorage
|
||||
localStorage.setItem('sidebarCollapsed', isCollapsed.value)
|
||||
}
|
||||
|
||||
// 切换移动端菜单
|
||||
const toggleMobileMenu = () => {
|
||||
isMobileMenuOpen.value = !isMobileMenuOpen.value
|
||||
}
|
||||
|
||||
// 关闭移动端菜单
|
||||
const closeMobileMenu = () => {
|
||||
isMobileMenuOpen.value = false
|
||||
}
|
||||
|
||||
// 切换全屏
|
||||
const toggleFullScreen = () => {
|
||||
if (!document.fullscreenElement) {
|
||||
@@ -129,9 +184,35 @@ const handleLogout = () => {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('tokenExpire')
|
||||
localStorage.removeItem('userInfo')
|
||||
userStore.clearUserInfo()
|
||||
router.push('/login')
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
// 监听路由变化,移动端自动关闭菜单
|
||||
router.afterEach(() => {
|
||||
if (isMobile.value) {
|
||||
closeMobileMenu()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 恢复侧边栏状态
|
||||
const savedState = localStorage.getItem('sidebarCollapsed')
|
||||
if (savedState !== null) {
|
||||
isCollapsed.value = savedState === 'true'
|
||||
}
|
||||
|
||||
// 检测设备类型
|
||||
checkMobile()
|
||||
window.addEventListener('resize', checkMobile)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', checkMobile)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -141,6 +222,18 @@ const handleLogout = () => {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 移动端遮罩层 */
|
||||
.mobile-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 998;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.sidebar {
|
||||
width: 260px;
|
||||
@@ -148,7 +241,15 @@ const handleLogout = () => {
|
||||
background-color: #ffffff;
|
||||
border-right: 1px solid #e1e8ed;
|
||||
overflow: hidden;
|
||||
z-index: 20;
|
||||
z-index: 999;
|
||||
transition: width 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
@@ -159,6 +260,7 @@ const handleLogout = () => {
|
||||
padding: 0 20px;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #e1e8ed;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
@@ -167,8 +269,15 @@ const handleLogout = () => {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.logo-img-mini {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.sidebar-scrollbar {
|
||||
height: calc(100vh - 70px);
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
@@ -178,6 +287,32 @@ const handleLogout = () => {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 收缩按钮 */
|
||||
.collapse-btn {
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top: 1px solid #e1e8ed;
|
||||
cursor: pointer;
|
||||
color: #7f8c8d;
|
||||
transition: all 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.collapse-btn:hover {
|
||||
color: #2c3e50;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* 移动端菜单按钮 */
|
||||
.mobile-menu-btn {
|
||||
display: none;
|
||||
margin-right: 12px;
|
||||
padding: 8px;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
/* 主容器样式 */
|
||||
.main-container {
|
||||
flex: 1;
|
||||
@@ -185,6 +320,7 @@ const handleLogout = () => {
|
||||
flex-direction: column;
|
||||
background-color: #f0f2f5;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 顶部导航栏样式 */
|
||||
@@ -197,18 +333,21 @@ const handleLogout = () => {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
z-index: 10;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
@@ -286,6 +425,63 @@ const handleLogout = () => {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* 移动端隐藏元素 */
|
||||
.hidden-mobile {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* 移动端响应式 */
|
||||
@media (max-width: 768px) {
|
||||
.mobile-overlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
left: -260px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: left 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 260px;
|
||||
left: -260px;
|
||||
}
|
||||
|
||||
.admin-layout.mobile-open .sidebar {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.admin-layout.mobile-open .sidebar.collapsed {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.collapse-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-menu-btn {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.hidden-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dropdown-menu) {
|
||||
border-radius: 0;
|
||||
border: 1px solid #e1e8ed;
|
||||
|
||||
Reference in New Issue
Block a user