BCVP.VUE3系列第十一课:基于总线实现框架多种布局样式

艺帆风顺 发布于 2025-04-03 30 次阅读


BCVP 开发者社区出品BCVP V3开发数字化服务化绿色化

放假不停歇,这一系列会从0开始学习VUE3,使用Vite、TS、Pinia、Element-Plus等新知识点,既是查漏补缺,也是知识分享。

代码地址:

https://github.com/anjoy8/bcvp.vue3.git

这是每篇文章一节课一个分支,方便大家学习,会慢慢的将blog.admin项目进行翻新,使用的后端接口还是BlogCore。

系列文章:

第一课:项目初始化与核心知识点说明

第二课:基于泛型基类封装Axios请求

第三课:封装Axios拦截器

第四课:登录页设计

第五课:获取用户信息

第六课:获取动态菜单接口

第七课:基于布局模式实现动态菜单渲染

第八课:丰富面包屑组件

第九课:实现tabs标签栏

第十课:个人中心模块

0、本文介绍

本文参考的是开源项目

https://gitee.com/HalseySpicy/Geeker-Admin/tree/template

分步骤讲解前端框架中的每一个核心逻辑,今天说一下通过mittBus工具实现框架多种样式布局,之前是纵向布局,今天实现横向布局,效果图:

因为有些时候,我们是需要这种横向布局的。

1、引入mittBus中间件

在 Vue 3 中,mittBus 是一个使用 mitt 库创建的事件总线(event bus)。mitt 是一个非常轻量的事件发射(emit)库,它可以用来在不同的组件之间发送和接收事件,从而实现组件之间的通信。

一、安装依赖:

二、创建事件总线:

通常,会在某个公共的地方(例如 utils/mittBus.js 文件)使用 mitt 创建一个事件总线实例:

新建srcutilsmittBus.ts

    import mitt from 'mitt';const mittBus = mitt();export default mittBus;

    三、发起事件

    根据需要,在右上角功能Bar中,增加定义一个主题设置按钮:

    新建文件

    srclayoutscomponentsHeadercomponentsThemeSetting.vue

      template> div class="theme-setting"> i :class="'iconfont icon-zhuti'" class="toolBar-icon" @click="openDrawer">i> div>template>
      script setup lang="ts">import mittBus from "@/utils/mittBus";const openDrawer = () => { mittBus.emit("openThemeDrawer");};script>

      这里当点击图标时,通过调用 mittBus.emit("openThemeDrawer") 发射一个名为 "openThemeDrawer" 的事件,

      四、最后,在ToolBarRight.vue组件中,引用主题设置组件

      这个时候就能看到效果了:

      接下来就需要对这个监听这个事件——目的就是唤起功能设置区域。

      2、设计主题设置组件

      主要包括布局样式(目前支持横向布局和纵向布局)和界面设置,当前也可以设置其他的、样式相关的设置,比如暗黑模式,或者主题色等等,根据我个人经验,有这两个布局已经够用了。

      新建文件

      srclayoutscomponentsThemeDrawerindex.vue

        template> el-drawer v-model="drawerVisible" title="布局设置" size="290px">  el-divider class="divider" content-position="center"> el-icon> Notification /> el-icon> 布局样式 el-divider> div class="layout-box"> el-tooltip effect="dark" content="纵向" placement="top" :show-after="200"> div :class="['layout-item layout-vertical', { 'is-active': layout == 'vertical' }]" @click="setLayout('vertical')"> div class="layout-dark">div> div class="layout-container"> div class="layout-light">div> div class="layout-content">div> div> el-icon v-if="layout == 'vertical'"> CircleCheckFilled /> el-icon> div> el-tooltip> el-tooltip effect="dark" content="横向" placement="top" :show-after="200"> div :class="['layout-item layout-transverse', { 'is-active': layout == 'transverse' }]" @click="setLayout('transverse')"> div class="layout-dark">div> div class="layout-content">div> el-icon v-if="layout == 'transverse'"> CircleCheckFilled /> el-icon> div> el-tooltip> div>
        el-divider class="divider" content-position="center"> el-icon> Setting /> el-icon> 界面设置 el-divider> div class="theme-item"> span>菜单折叠span> el-switch v-model="isCollapse" /> div> div class="theme-item"> span>菜单手风琴span> el-switch v-model="accordion" /> div> div class="theme-item"> span>面包屑span> el-switch v-model="breadcrumb" /> div> div class="theme-item"> span>面包屑图标span> el-switch v-model="breadcrumbIcon" /> div> div class="theme-item"> span>标签栏span> el-switch v-model="tabs" /> div> div class="theme-item"> span>标签栏图标span> el-switch v-model="tabsIcon" /> div> div class="theme-item"> span>页脚span> el-switch v-model="footer" /> div> el-drawer>template>
        script setup lang="ts">import { ref } from "vue";import { storeToRefs } from "pinia";import { useGlobalStore } from "@/stores/modules/global";import type { LayoutType } from "@/stores/interface";import mittBus from "@/utils/mittBus";
        const globalStore = useGlobalStore();const { layout, isCollapse, accordion, breadcrumb, breadcrumbIcon, tabs, tabsIcon, footer } = storeToRefs(globalStore);
        // 设置布局方式const setLayout = (val: LayoutType) => { globalStore.setGlobalState("layout", val);};
        // 打开主题设置const drawerVisible = ref(false);mittBus.on("openThemeDrawer", () => { drawerVisible.value = true});script>
        style scoped lang="scss">@import "./index.scss";style>

        可以看到,在90行代码,有一个对主题设置的总线监听方法,就是用来处理设置页面发射的事件的处理。

        最后,在layout母版布局页,引用该setting组件即可

        点击右上角的主题设置按钮,就能唤起设置菜单了。

        3、设计横向布局layout

        在之前,我们写过一个纵向的布局,那现在追加一个新的横向菜单布局的效果,新建文件:

        srclayoutsLayoutTransverseindex.vue

          template> el-container class="layout"> el-header> div class="logo flx-center"> img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> span class="logo-text">{{ title }}span> div> el-menu mode="horizontal" :router="false" :default-active="activeMenu">  template v-for="subItem in menuList" :key="subItem.name"> el-sub-menu v-if="subItem.children?.length" :key="subItem.name" :index="subItem.name + 'el-sub-menu'"> template #title> el-icon> component :is="subItem.meta.icon">component> el-icon> span>{{ subItem.meta.title }}span> template> SubMenu :menu-list="subItem.children" /> el-sub-menu> el-menu-item v-else :key="subItem.path + 'el-menu-item'" :index="subItem.path" @click="handleClickMenu(subItem)"> el-icon> component :is="subItem.meta.icon">component> el-icon> template #title> span>{{ subItem.meta.title }}span> template> el-menu-item> template> el-menu> ToolBarRight /> el-header> Main /> el-container>template>
          script setup lang="ts" name="layoutTransverse">import { computed } from "vue";import { useAuthMenuStore } from "@/stores/modules/authMenu";import { useRoute, useRouter } from "vue-router";import Main from "@/layouts/components/Main/index.vue";import ToolBarRight from "@/layouts/components/Header/ToolBarRight.vue";import SubMenu from "@/layouts/components/Menu/SubMenu.vue";
          const title = 'BlogVue3';
          const route = useRoute();const router = useRouter();const authStore = useAuthMenuStore();const menuList = computed(() => authStore.showMenuListGet);const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string);
          const handleClickMenu = (subItem: Menu.MenuOptions) => { if (subItem.meta.isLink) return window.open(subItem.meta.isLink, "_blank"); router.push(subItem.path);};script>
          style scoped lang="scss">@import "./index.scss";style>

          然后在layout母版中,引入第二种布局组件,当我们在唤起的样式布局中,切换样式的时候,传值到了Pinia状态管理器,这里通过computed可以实时响应对应的类型名,从而渲染不同的模板组件,从而实现不同的效果

          页面切换布局效果,可以看到横向和纵向的动态变化,只不过还是老问题,刷新页面后,数据就回到了默认的纵向布局状态了,所以还是需要用到持久化方案。

          4、模板文件引用,渲染效果

          这个例子又一次证明,使用Pinia和localstorage可以完美实现对所有的数据的操作和管理操作,还是建议多多使用。

          在global.ts的状态管理器中,增加Pinia配置插件

          最终的渲染效果,没问题,试试路由跳转和页面刷新都没问题

          下篇文章我们继续对框架进行更新,开启页面级别的数据填充,实现表格渲染,敬请期待。