这段代码是一个基于 Vue3 的基础布局组件(BaseLayout),主要用于构建应用的页面布局,支持多种布局模式(垂直、水平及其混合模式),通过 Vuex 管理状态,动态计算和渲染各个部分的布局和样式。组件结构清晰,功能完善,适配不同设备和主题配置。以下是对代码的详细解读:
1. 导入依赖
import { computed, defineAsyncComponent } from 'vue';
import { AdminLayout, LAYOUT_SCROLL_EL_ID } from '@sa/materials';
import type { LayoutMode } from '@sa/materials';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import GlobalHeader from '../modules/global-header/index.vue';
import GlobalSider from '../modules/global-sider/index.vue';
import GlobalTab from '../modules/global-tab/index.vue';
import GlobalContent from '../modules/global-content/index.vue';
import GlobalFooter from '../modules/global-footer/index.vue';
import ThemeDrawer from '../modules/theme-drawer/index.vue';
import { setupMixMenuContext } from '../context';
-
导入 Vue3 的核心函数
computed
和defineAsyncComponent
。 -
从
@sa/materials
导入布局组件AdminLayout
和相关类型。 -
导入 Vuex 的 store 模块
useAppStore
和useThemeStore
,用于管理应用状态和主题配置。 -
导入各个子组件,如头部、侧边栏、标签页、内容区、页脚等。
-
导入菜单上下文设置函数
setupMixMenuContext
。
2. 定义组件选项
defineOptions({
name: 'BaseLayout'
});
-
使用
defineOptions
定义组件的选项,设置组件名为BaseLayout
。
3. 获取状态和上下文
const appStore = useAppStore();
const themeStore = useThemeStore();
const { childLevelMenus, isActiveFirstLevelMenuHasChildren } = setupMixMenuContext();
-
获取 Vuex store 中的
appStore
和themeStore
实例,用于访问应用和主题相关的状态。 -
调用
setupMixMenuContext
获取菜单相关的上下文数据,包括子菜单列表和是否激活一级菜单有子菜单的标志。
4. 定义异步组件
const GlobalMenu = defineAsyncComponent(() => import('../modules/global-menu/index.vue'));
-
使用
defineAsyncComponent
定义异步加载的GlobalMenu
组件,按需加载以优化性能。
5. 计算布局模式
const layoutMode = computed(() => {
const vertical: LayoutMode = 'vertical';
const horizontal: LayoutMode = 'horizontal';
return themeStore.layout.mode.includes(vertical) ? vertical : horizontal;
});
-
定义计算属性
layoutMode
,根据主题配置中的布局模式判断是垂直模式还是水平模式。
6. 计算头部属性
const headerProps = computed(() => {
const { mode, reverseHorizontalMix } = themeStore.layout;
const headerPropsConfig: Record<UnionKey.ThemeLayoutMode, App.Global.HeaderProps> = {
vertical: {
showLogo: false,
showMenu: false,
showMenuToggler: true
},
'vertical-mix': {
showLogo: false,
showMenu: false,
showMenuToggler: false
},
horizontal: {
showLogo: true,
showMenu: true,
showMenuToggler: false
},
'horizontal-mix': {
showLogo: true,
showMenu: true,
showMenuToggler: reverseHorizontalMix && isActiveFirstLevelMenuHasChildren.value
}
};
return headerPropsConfig[mode];
});
-
定义计算属性
headerProps
,根据不同的布局模式配置头部的显示属性,如是否显示 Logo、菜单、菜单切换器等。
7. 计算侧边栏相关属性
const siderVisible = computed(() => themeStore.layout.mode !== 'horizontal');
const isVerticalMix = computed(() => themeStore.layout.mode === 'vertical-mix');
const isHorizontalMix = computed(() => themeStore.layout.mode === 'horizontal-mix');
const siderWidth = computed(() => getSiderWidth());
const siderCollapsedWidth = computed(() => getSiderCollapsedWidth());
-
定义多个计算属性,判断侧边栏是否可见、是否是垂直混合模式、是否是水平混合模式,以及计算侧边栏的宽度和折叠宽度。
8. 获取侧边栏宽度和折叠宽度的方法
function getSiderWidth() {
const { reverseHorizontalMix } = themeStore.layout;
const { width, mixWidth, mixChildMenuWidth } = themeStore.sider;
if (isHorizontalMix.value && reverseHorizontalMix) {
return isActiveFirstLevelMenuHasChildren.value ? width : 0;
}
let w = isVerticalMix.value || isHorizontalMix.value ? mixWidth : width;
if (isVerticalMix.value && appStore.mixSiderFixed && childLevelMenus.value.length) {
w += mixChildMenuWidth;
}
return w;
}
function getSiderCollapsedWidth() {
const { reverseHorizontalMix } = themeStore.layout;
const { collapsedWidth, mixCollapsedWidth, mixChildMenuWidth } = themeStore.sider;
if (isHorizontalMix.value && reverseHorizontalMix) {
return isActiveFirstLevelMenuHasChildren.value ? collapsedWidth : 0;
}
let w = isVerticalMix.value || isHorizontalMix.value ? mixCollapsedWidth : collapsedWidth;
if (isVerticalMix.value && appStore.mixSiderFixed && childLevelMenus.value.length) {
w += mixChildMenuWidth;
}
return w;
}
-
getSiderWidth
和getSiderCollapsedWidth
方法根据不同的布局模式和配置,动态计算侧边栏的宽度和折叠宽度,考虑了混合模式下的特殊情况。
9. 模板部分
<template>
<AdminLayout
v-model:sider-collapse="appStore.siderCollapse"
:mode="layoutMode"
:scroll-el-id="LAYOUT_SCROLL_EL_ID"
:scroll-mode="themeStore.layout.scrollMode"
:is-mobile="appStore.isMobile"
:full-content="appStore.fullContent"
:fixed-top="themeStore.fixedHeaderAndTab"
:header-height="themeStore.header.height"
:tab-visible="themeStore.tab.visible"
:tab-height="themeStore.tab.height"
:content-class="appStore.contentXScrollable ? 'overflow-x-hidden' : ''"
:sider-visible="siderVisible"
:sider-width="siderWidth"
:sider-collapsed-width="siderCollapsedWidth"
:footer-visible="themeStore.footer.visible"
:footer-height="themeStore.footer.height"
:fixed-footer="themeStore.footer.fixed"
:right-footer="themeStore.footer.right"
>
<template #header>
<GlobalHeader v-bind="headerProps" />
</template>
<template #tab>
<GlobalTab />
</template>
<template #sider>
<GlobalSider />
</template>
<GlobalMenu />
<GlobalContent />
<ThemeDrawer />
<template #footer>
<GlobalFooter />
</template>
</AdminLayout>
</template>
-
使用
AdminLayout
作为主布局组件,通过v-model:sider-collapse
双向绑定侧边栏的折叠状态。 -
通过
:mode
绑定布局模式,其他属性根据主题配置和计算属性动态设置。 -
使用插槽渲染头部、标签页、侧边栏、内容区、页脚等子组件。
-
GlobalMenu
、GlobalContent
和ThemeDrawer
直接渲染在布局中。
10. 样式部分
<style lang="scss">
#__SCROLL_EL_ID__ {
@include scrollbar();
}
</style>
-
定义滚动条的样式,使用 SCSS 的
@include
混入scrollbar
样式。