101 lines
3.1 KiB
Vue
101 lines
3.1 KiB
Vue
<template>
|
|
<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>
|
|
|
|
<!-- 桌面端侧边栏 -->
|
|
<div
|
|
v-if="sidebar.length && !isMobile"
|
|
class="hidden md:block mr-4 bg-white rounded-[8px] overflow-hidden"
|
|
>
|
|
<Menu
|
|
:menu="sidebar"
|
|
:default-active="activeMenu"
|
|
mode="vertical"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 移动端抽屉式侧边栏 -->
|
|
<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>
|
|
|
|
<!-- 主内容区域 -->
|
|
<div
|
|
:class="[
|
|
'layout-page flex-1 min-w-0 rounded-[8px] transition-all duration-300',
|
|
{
|
|
'bg-body': hasSidebar,
|
|
'md:ml-0': !isMobile || !sidebar.length,
|
|
'ml-0': isMobile && sidebar.length
|
|
}
|
|
]"
|
|
>
|
|
<slot />
|
|
</div>
|
|
</main>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import Menu from '../menu/index.vue'
|
|
import { ref, onMounted, onUnmounted } from 'vue'
|
|
|
|
const route = useRoute()
|
|
const activeMenu = computed<string>(() => route.meta.activeMenu ?? route.path)
|
|
const { sidebar, hasSidebar } = useMenu()
|
|
|
|
// 响应式判断
|
|
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> |