180 lines
4.1 KiB
Vue
Raw Normal View History

2023-07-06 13:02:52 +08:00
<script lang="ts" setup>
import { useDevice } from "@/composables/useDevice"
import { useLayoutMode } from "@/composables/useLayoutMode"
import { useAppStore } from "@/pinia/stores/app"
import { useSettingsStore } from "@/pinia/stores/settings"
2024-11-18 19:40:44 +08:00
import { storeToRefs } from "pinia"
import { computed } from "vue"
2024-11-26 11:42:24 +08:00
import { AppMain, NavigationBar, Sidebar, TagsView } from "../components"
2023-07-06 13:02:52 +08:00
2024-02-06 13:39:56 +08:00
const { isMobile } = useDevice()
const { isLeft } = useLayoutMode()
2023-07-06 13:02:52 +08:00
const appStore = useAppStore()
const settingsStore = useSettingsStore()
const { showTagsView, fixedHeader } = storeToRefs(settingsStore)
/** 定义计算属性 layoutClasses用于控制布局的类名 */
const layoutClasses = computed(() => {
return {
hideSidebar: !appStore.sidebar.opened,
openSidebar: appStore.sidebar.opened,
withoutAnimation: appStore.sidebar.withoutAnimation,
mobile: isMobile.value,
noLeft: !isLeft.value
2023-07-06 13:02:52 +08:00
}
})
/** 用于处理点击 mobile 端侧边栏遮罩层的事件 */
2024-11-18 19:40:44 +08:00
function handleClickOutside() {
2023-07-06 13:02:52 +08:00
appStore.closeSidebar(false)
}
</script>
<template>
<div :class="layoutClasses" class="app-wrapper">
<!-- mobile 端侧边栏遮罩层 -->
<div v-if="layoutClasses.mobile && layoutClasses.openSidebar" class="drawer-bg" @click="handleClickOutside" />
<!-- 左侧边栏 -->
<Sidebar class="sidebar-container" />
<!-- 主容器 -->
<div :class="{ hasTagsView: showTagsView }" class="main-container">
<!-- 头部导航栏和标签栏 -->
<div :class="{ 'fixed-header': fixedHeader }" class="layout-header">
<NavigationBar />
<TagsView v-show="showTagsView" />
</div>
<!-- 页面主体内容 -->
<AppMain class="app-main" />
</div>
</div>
</template>
<style lang="scss" scoped>
@import "@/assets/styles/mixins.scss";
2023-07-06 13:02:52 +08:00
$transition-time: 0.35s;
.app-wrapper {
@extend %clearfix;
2023-07-06 13:02:52 +08:00
position: relative;
width: 100%;
}
.drawer-bg {
2024-03-28 21:34:24 +08:00
background-color: rgba(0, 0, 0, 0.3);
2023-07-06 13:02:52 +08:00
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.sidebar-container {
2023-07-19 09:05:55 +08:00
background-color: var(--v3-sidebar-menu-bg-color);
2023-07-06 13:02:52 +08:00
transition: width $transition-time;
2024-11-21 11:03:40 +08:00
width: var(--v3-sidebar-width);
2023-07-06 13:02:52 +08:00
height: 100%;
position: fixed;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
border-right: var(--v3-sidebar-border-right);
2023-07-06 13:02:52 +08:00
}
.main-container {
min-height: 100%;
transition: margin-left $transition-time;
margin-left: var(--v3-sidebar-width);
position: relative;
}
.fixed-header {
position: fixed !important;
2023-07-06 13:02:52 +08:00
top: 0;
right: 0;
z-index: 9;
width: calc(100% - var(--v3-sidebar-width));
transition: width $transition-time;
}
.layout-header {
position: relative;
z-index: 9;
2024-03-28 21:34:24 +08:00
background-color: var(--v3-header-bg-color);
box-shadow: var(--v3-header-box-shadow);
border-bottom: var(--v3-header-border-bottom);
2023-07-06 13:02:52 +08:00
}
.app-main {
min-height: calc(100vh - var(--v3-navigationbar-height));
position: relative;
overflow: hidden;
}
.fixed-header + .app-main {
padding-top: var(--v3-navigationbar-height);
height: 100vh;
overflow: auto;
}
.hasTagsView {
.app-main {
min-height: calc(100vh - var(--v3-header-height));
}
.fixed-header + .app-main {
padding-top: var(--v3-header-height);
}
}
.hideSidebar {
.sidebar-container {
2024-11-21 11:03:40 +08:00
width: var(--v3-sidebar-hide-width);
2023-07-06 13:02:52 +08:00
}
.main-container {
margin-left: var(--v3-sidebar-hide-width);
}
.fixed-header {
width: calc(100% - var(--v3-sidebar-hide-width));
}
}
// 适配 mobile 端
.mobile {
.sidebar-container {
transition: transform $transition-time;
2024-11-21 11:03:40 +08:00
width: var(--v3-sidebar-width);
2023-07-06 13:02:52 +08:00
}
.main-container {
margin-left: 0px;
}
.fixed-header {
width: 100%;
}
&.openSidebar {
position: fixed;
top: 0;
}
&.hideSidebar {
.sidebar-container {
pointer-events: none;
transition-duration: 0.3s;
transform: translate3d(calc(0px - var(--v3-sidebar-width)), 0, 0);
}
}
2024-11-21 12:41:24 +08:00
// 既是 mobile 又是顶部或混合布局模式
&.noLeft {
.sidebar-container {
background-color: var(--el-bg-color);
}
}
2023-07-06 13:02:52 +08:00
}
.withoutAnimation {
.sidebar-container,
.main-container {
transition: none;
}
}
</style>