放假不停歇,这一系列会从0开始学习VUE3,使用Vite、TS、Pinia、Element-Plus等新知识点,既是查漏补缺,也是知识分享。
代码地址:
https://github.com/anjoy8/bcvp.vue3.git
这是每篇文章一节课一个分支,方便大家学习,会慢慢的将blog.admin项目进行翻新,使用的后端接口还是BlogCore。
系列文章:
本文参考的是开源项目
https://gitee.com/HalseySpicy/Geeker-Admin/tree/template
分步骤讲解前端框架中的每一个核心逻辑,今天说一下通过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组件中,引用主题设置组件

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

接下来就需要对这个监听这个事件——目的就是唤起功能设置区域。
主要包括布局样式(目前支持横向布局和纵向布局)和界面设置,当前也可以设置其他的、样式相关的设置,比如暗黑模式,或者主题色等等,根据我个人经验,有这两个布局已经够用了。
新建文件
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组件即可

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

在之前,我们写过一个纵向的布局,那现在追加一个新的横向菜单布局的效果,新建文件:
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可以实时响应对应的类型名,从而渲染不同的模板组件,从而实现不同的效果


页面切换布局效果,可以看到横向和纵向的动态变化,只不过还是老问题,刷新页面后,数据就回到了默认的纵向布局状态了,所以还是需要用到持久化方案。
这个例子又一次证明,使用Pinia和localstorage可以完美实现对所有的数据的操作和管理操作,还是建议多多使用。
在global.ts的状态管理器中,增加Pinia配置插件

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

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