基于 Vue3 的基础布局组件(BaseLayout)

这段代码是一个基于 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 的核心函数 computeddefineAsyncComponent

  • @sa/materials 导入布局组件 AdminLayout 和相关类型。

  • 导入 Vuex 的 store 模块 useAppStoreuseThemeStore,用于管理应用状态和主题配置。

  • 导入各个子组件,如头部、侧边栏、标签页、内容区、页脚等。

  • 导入菜单上下文设置函数 setupMixMenuContext

2. 定义组件选项

defineOptions({
  name: 'BaseLayout'
});
  • 使用 defineOptions 定义组件的选项,设置组件名为 BaseLayout

3. 获取状态和上下文

const appStore = useAppStore();
const themeStore = useThemeStore();
const { childLevelMenus, isActiveFirstLevelMenuHasChildren } = setupMixMenuContext();
  • 获取 Vuex store 中的 appStorethemeStore 实例,用于访问应用和主题相关的状态。

  • 调用 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;
}
  • getSiderWidthgetSiderCollapsedWidth 方法根据不同的布局模式和配置,动态计算侧边栏的宽度和折叠宽度,考虑了混合模式下的特殊情况。

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 绑定布局模式,其他属性根据主题配置和计算属性动态设置。

  • 使用插槽渲染头部、标签页、侧边栏、内容区、页脚等子组件。

  • GlobalMenuGlobalContentThemeDrawer 直接渲染在布局中。

10. 样式部分

<style lang="scss">
#__SCROLL_EL_ID__ {
  @include scrollbar();
}
</style>
  • 定义滚动条的样式,使用 SCSS 的 @include 混入 scrollbar 样式。

### Vue3 项目中的 Layout 布局配置与实现 在现代前端开发中,Vue3 提供了强大的工具链来简化应用的创建过程。对于布局(Layout)的设计,在Vue3中有多种方式可以实现。 #### 使用 `vue-router` 实现多层嵌套路由视图 为了设置全局性的页面结构(Header, Footer 或者侧边栏),通常会采用单文件组件(SFCs)配合路由守卫的方式。下面是一个简单的例子展示如何利用 `vue-router` 来管理不同页面间的公共区域: 1. **安装依赖** 需要先确保已经安装了 `@vue/cli-plugin-babel`, `@vue/cli-service` 和 `vue-router`. 如果还没有的话可以通过 npm 安装: ```bash npm install vue-router@next --save ``` 2. **创建基础布局组件** 创建一个新的名为 `Layout.vue` 的 SFC 文件作为项目的默认布局容器: ```html <!-- src/views/Layout.vue --> <template> <div class="app-container"> <header>这是头部</header> <main> <router-view></router-view> </main> <footer>这是底部</footer> </div> </template> <script lang="ts"> import { defineComponent } from &#39;vue&#39;; export default defineComponent({ name: "AppLayout", }); </script> <style scoped> .app-container { display: flex; min-height: 100vh; flex-direction: column; } header, footer { background-color: #f8f9fa; padding: 1rem; text-align: center; } </style> ``` 3. **配置路由规则** 接下来修改 `src/router/index.ts` 中的内容以适应新的布局需求: ```typescript // src/router/index.ts import { createRouter, createWebHistory, RouteRecordRaw } from &#39;vue-router&#39;; import HomeView from &#39;../views/HomeView.vue&#39;; import AboutView from &#39;../views/AboutView.vue&#39;; import AppLayout from &#39;@/components/AppLayout.vue&#39;; // 导入自定义布局 const routes: Array<RouteRecordRaw> = [ { path: &#39;/&#39;, component: AppLayout, children:[ { path: &#39;&#39;, name: &#39;home&#39;, component: HomeView }, { path: &#39;/about&#39;, name: &#39;about&#39;, component: AboutView } ] } ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }); export default router; ``` 4. **调整入口文件** 修改 `main.ts` 让整个应用程序包裹在一个根级别的 `<Suspense>` 组件内,从而更好地处理异步加载逻辑: ```typescript // main.ts import { createApp } from &#39;vue&#39;; import App from &#39;./App.vue&#39;; import router from &#39;./router&#39;; createApp(App).use(router).mount(&#39;#app&#39;); ``` 以上就是基于 Vue Router 构建的基础布局模式[^1]。这种方式允许开发者轻松地为多个子页面共享相同的顶部导航条或页脚等内容,并且能够很好地与其他功能特性集成在一起。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值