本章分析页面布局详解详解
ObJack-Admin一款基于 Vue3.3、TypeScript、Vite3、Pinia、Element-Plus 开源的后台管理框架。在一定程度上节省您的开发效率。另外本项目还封装了一些常用组件、hooks、指令、动态路由、按钮级别权限控制等功能。感兴趣的小伙伴可以访问源码点个赞 地址
所有的动态路由都添加在了layout组件下,所以直接打开layout查看,路径为 layouts/index.vue
此处逻辑很简单就不细说了,就是通过 component
动态加载组件下边的四种布局结构。
const LayoutComponents: Record<LayoutType, Component> = {vertical: LayoutVertical,classic: LayoutClassic,transverse: LayoutTransverse,columns: LayoutColumns
};
大家可以发现,默认加载的是 vertical: LayoutVertical
组件,所以我们打开这个文件查看一下。
基本布局就是下边这样的
<el-container class="layout"><el-aside>logo和菜单</el-aside><el-container>头部、主体内容、底部</el-container>
</el-container>
- 菜单分析
<el-menu:router="false":default-active="activeMenu":collapse="isCollapse":unique-opened="accordion":collapse-transition="false"><SubMenu :menu-list="menuList" />
</el-menu>
首先看一下 menuList 怎么来的。
const menuList = computed(() => authStore.showMenuListGet);
通过这句代码可以发现是通过 pinia 获取来的。
接着查找,找到 auth.ts 文件,路径为 stores/modules/auth.ts
// 菜单权限列表 ==> 左侧菜单栏渲染,需要剔除 isHide == trueshowMenuListGet: state => getShowMenuList(state.authMenuList),
可以看到是通过 getShowMenuList 方法返回来的。
分析 getShowMenuList 方法之前我们先看一下 authMenuList 是怎么来的。
async getAuthMenuList() {const { data } = await getAuthMenuListApi();this.authMenuList = data;},
加载动态路由的时候已经调用了此方法,在 dynamicRouter 文件中。
await authStore.getAuthMenuList();
接着找到 getAuthMenuListApi 方法
export const getAuthMenuListApi = () => {// return http.get<Menu.MenuOptions[]>(PORT1 + `/menu/list`, {}, { loading: false });// 如果想让菜单变为本地数据,注释上一行代码,并引入本地 authMenuList.json 数据return authMenuList;
};
这就是authMenuList的封装
好了,接下来咱们分析一下 getShowMenuList 方法。
export function getShowMenuList(menuList: Menu.MenuOptions[]) {let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));return newMenuList.filter(item => {item.children?.length && (item.children = getShowMenuList(item.children));return !item.meta?.isHide;});
}
首先把 menuList 深拷贝 赋值给 newMenuList。(如果大家不懂何为深拷贝的话,可以自行去查找相关资料)
接下来就是递归调用此方法,过滤掉到 isHide=true 的数据, 因为 isHide 为 true 的话代表隐藏菜单,不需要展示。
想了想,担心有的同学看不懂递归的这一部分逻辑,还是展开说说吧。
-
- 调用数组filter方法遍历筛选对应的数组。
-
- item.children?.length 此处的?写法就是判断children是否存在,存在的话就取length,不存在的话就不往下走了,下边的 item.meta?.isHide 也如此。
-
- item.children = getShowMenuList(item.children) 这段代码的意思就是将 getShowMenuList 方法的结果赋值给item.children,那getShowMenuList的返回结果是什么呢?其实就是每次循环 isHide 不为 true 的数据。
接下来就分析菜单是怎么渲染上去的,查看 SubMenu 文件,路径在 /layouts/components/Menu/SubMenu.vue
- item.children = getShowMenuList(item.children) 这段代码的意思就是将 getShowMenuList 方法的结果赋值给item.children,那getShowMenuList的返回结果是什么呢?其实就是每次循环 isHide 不为 true 的数据。
<template v-for="subItem in menuList" :key="subItem.path"><el-sub-menu v-if="subItem.children?.length" :index="subItem.path"><template #title><el-icon v-if="subItem.meta.icon"><component :is="subItem.meta.icon"></component></el-icon><span class="sle">{{ subItem.meta.title }}</span></template><SubMenu :menu-list="subItem.children" /></el-sub-menu><el-menu-item v-else :index="subItem.path" @click="handleClickMenu(subItem)"><el-icon v-if="subItem.meta.icon"><component :is="subItem.meta.icon"></component></el-icon><template #title><span class="sle">{{ subItem.meta.title }}</span></template></el-menu-item></template>
其实这一部门逻辑也很简单,主要是循环判断有没有children 子目录,有的话就调用 el-sub-menu 组件,没有的话就调用 el-menu-item 组件,其中值得一说的是 下边这一段代码。
<component :is="subItem.meta.icon"></component>
大家应该还记得在 main.js 中 通过循环创建了 icon 公共组件,这里就是加载对应的icon组件。
至此,动态菜单就完成了。
2. 头部
这一部分逻辑也简单,大家有不懂得可以私信。
说一下面包屑是怎么渲染的吧,重点说一下下面这部分。
const breadcrumbList = computed(() => {let breadcrumbData = authStore.breadcrumbListGet[route.matched[route.matched.length - 1].path] ?? [];// 🙅♀️不需要首页面包屑可删除以下判断if (breadcrumbData[0].path !== HOME_URL) {breadcrumbData = [{ path: HOME_URL, meta: { icon: "HomeFilled", title: "首页" } }, ...breadcrumbData];}return breadcrumbData;
});
-
- 每次从 authStore.breadcrumbListGet 中获取当前路由的最后一个path 作为 key 的面包屑数据
-
- ?? 是 空值合并运算符 ,意思就是如果 ?? 左侧的结果是null或者undefined 的话,就取 ?? 右侧的数据,上边代码就是如果从 authStore.breadcrumbListGet 获取不到对应数据的话,那么本次就是空数据。
-
- 接下来就是给 breadcrumbData 添加了一条首页的面包屑,使用的三点运算符。
如碰到其他的问题 可以私下我 一起探讨学习
如果对你有所帮助还请 点赞 收藏谢谢~!
关注收藏博客 作者会持续更新…