edu/pc/layouts/components/main/index.vue

101 lines
3.1 KiB
Vue
Raw Normal View History

2025-11-28 07:29:47 +00:00
<template>
2025-12-04 01:39:51 +00:00
<main class="mx-auto py-4 flex" style="min-width: 62vw; min-height: 100vh">
<!-- 移动端菜单按钮 -->
<button
v-if="sidebar.length && isMobile"
@click="showMobileMenu = true"
class="fixed left-4 top-[68px] z-50 md:hidden p-2 rounded-full bg-white shadow-lg transition-all duration-300"
:class="{ '-translate-x-full': showMobileMenu, 'translate-x-0': !showMobileMenu }"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
</button>
<!-- 桌面端侧边栏 -->
2025-11-28 07:29:47 +00:00
<div
2025-12-04 01:39:51 +00:00
v-if="sidebar.length && !isMobile"
class="hidden md:block mr-4 bg-white rounded-[8px] overflow-hidden"
2025-11-28 07:29:47 +00:00
>
<Menu
:menu="sidebar"
:default-active="activeMenu"
mode="vertical"
/>
</div>
2025-12-04 01:39:51 +00:00
<!-- 移动端抽屉式侧边栏 -->
<div
v-if="sidebar.length && isMobile"
class="fixed inset-0 z-40"
:class="{'pointer-events-none': !showMobileMenu}"
>
<!-- 遮罩层 -->
<div
v-if="showMobileMenu"
@click="showMobileMenu = false"
class="absolute inset-0 transition-opacity"
/>
<!-- 侧边栏内容 -->
<div
class="absolute top-[60px] left-0 h-full w-64 bg-white transform transition-transform duration-300"
:class="{'translate-x-0': showMobileMenu, '-translate-x-full': !showMobileMenu}"
>
<Menu
:menu="sidebar"
:default-active="activeMenu"
mode="vertical"
@click="showMobileMenu = false"
/>
</div>
</div>
<!-- 主内容区域 -->
2025-11-28 07:29:47 +00:00
<div
:class="[
2025-12-04 01:39:51 +00:00
'layout-page flex-1 min-w-0 rounded-[8px] transition-all duration-300',
2025-11-28 07:29:47 +00:00
{
2025-12-04 01:39:51 +00:00
'bg-body': hasSidebar,
'md:ml-0': !isMobile || !sidebar.length,
'ml-0': isMobile && sidebar.length
2025-11-28 07:29:47 +00:00
}
]"
>
<slot />
</div>
</main>
</template>
2025-12-04 01:39:51 +00:00
2025-11-28 07:29:47 +00:00
<script lang="ts" setup>
import Menu from '../menu/index.vue'
2025-12-04 01:39:51 +00:00
import { ref, onMounted, onUnmounted } from 'vue'
2025-11-28 07:29:47 +00:00
const route = useRoute()
const activeMenu = computed<string>(() => route.meta.activeMenu ?? route.path)
const { sidebar, hasSidebar } = useMenu()
2025-12-04 01:39:51 +00:00
// 响应式判断
const isMobile = ref(false)
const showMobileMenu = ref(false)
const checkMobile = () => {
isMobile.value = window.outerWidth < 768 // 使用 Tailwind 的 md 断点
}
onMounted(() => {
checkMobile()
window.addEventListener('resize', checkMobile)
})
onUnmounted(() => {
window.removeEventListener('resize', checkMobile)
})
// 路由变化时关闭移动端菜单
watch(() => route.path, () => {
if (isMobile.value) {
showMobileMenu.value = false
}
})
</script>