从0-1搭建一个web项目(页面布局详解)详解

本章分析页面布局详解详解

ObJack-Admin一款基于 Vue3.3、TypeScript、Vite3、Pinia、Element-Plus 开源的后台管理框架。在一定程度上节省您的开发效率。另外本项目还封装了一些常用组件、hooks、指令、动态路由、按钮级别权限控制等功能。感兴趣的小伙伴可以访问源码点个赞 地址

所有的动态路由都添加在了layout组件下,所以直接打开layout查看,路径为 layouts/index.vue

此处逻辑很简单就不细说了,就是通过 component 动态加载组件下边的四种布局结构。

javascript 复制代码
const LayoutComponents: Record<LayoutType, Component> = {
  vertical: LayoutVertical,
  classic: LayoutClassic,
  transverse: LayoutTransverse,
  columns: LayoutColumns
};

大家可以发现,默认加载的是 vertical: LayoutVertical 组件,所以我们打开这个文件查看一下。

基本布局就是下边这样的

javascript 复制代码
<el-container class="layout">
    <el-aside>
        logo和菜单
     </el-aside>
 
    <el-container>
        头部、主体内容、底部
    </el-container>
</el-container>
  1. 菜单分析
javascript 复制代码
<el-menu
     :router="false"
     :default-active="activeMenu"
     :collapse="isCollapse"
     :unique-opened="accordion"
     :collapse-transition="false"
      >
      <SubMenu :menu-list="menuList" />
</el-menu>

首先看一下 menuList 怎么来的。

javascript 复制代码
const menuList = computed(() => authStore.showMenuListGet);

通过这句代码可以发现是通过 pinia 获取来的。

接着查找,找到 auth.ts 文件,路径为 stores/modules/auth.ts

javascript 复制代码
// 菜单权限列表 ==> 左侧菜单栏渲染,需要剔除 isHide == true
    showMenuListGet: state => getShowMenuList(state.authMenuList),

可以看到是通过 getShowMenuList 方法返回来的。

分析 getShowMenuList 方法之前我们先看一下 authMenuList 是怎么来的。

javascript 复制代码
async getAuthMenuList() {
      const { data } = await getAuthMenuListApi();
      this.authMenuList = data;
    },

加载动态路由的时候已经调用了此方法,在 dynamicRouter 文件中。

javascript 复制代码
await authStore.getAuthMenuList();

接着找到 getAuthMenuListApi 方法

javascript 复制代码
export const getAuthMenuListApi = () => {
  // return http.get<Menu.MenuOptions[]>(PORT1 + `/menu/list`, {}, { loading: false });
  // 如果想让菜单变为本地数据,注释上一行代码,并引入本地 authMenuList.json 数据
  return authMenuList;
};

这就是authMenuList的封装

好了,接下来咱们分析一下 getShowMenuList 方法。

javascript 复制代码
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 的话代表隐藏菜单,不需要展示。

想了想,担心有的同学看不懂递归的这一部分逻辑,还是展开说说吧。

    1. 调用数组filter方法遍历筛选对应的数组。
    1. item.children?.length 此处的?写法就是判断children是否存在,存在的话就取length,不存在的话就不往下走了,下边的 item.meta?.isHide 也如此。
    1. item.children = getShowMenuList(item.children) 这段代码的意思就是将 getShowMenuList 方法的结果赋值给item.children,那getShowMenuList的返回结果是什么呢?其实就是每次循环 isHide 不为 true 的数据。
      接下来就分析菜单是怎么渲染上去的,查看 SubMenu 文件,路径在 /layouts/components/Menu/SubMenu.vue
javascript 复制代码
<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 组件,其中值得一说的是 下边这一段代码。

javascript 复制代码
<component :is="subItem.meta.icon"></component>

大家应该还记得在 main.js 中 通过循环创建了 icon 公共组件,这里就是加载对应的icon组件。

至此,动态菜单就完成了。

2. 头部

这一部分逻辑也简单,大家有不懂得可以私信。

说一下面包屑是怎么渲染的吧,重点说一下下面这部分。

javascript 复制代码
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;
});
 
    1. 每次从 authStore.breadcrumbListGet 中获取当前路由的最后一个path 作为 key 的面包屑数据
    1. ?? 是 空值合并运算符 ,意思就是如果 ?? 左侧的结果是null或者undefined 的话,就取 ?? 右侧的数据,上边代码就是如果从 authStore.breadcrumbListGet 获取不到对应数据的话,那么本次就是空数据。
    1. 接下来就是给 breadcrumbData 添加了一条首页的面包屑,使用的三点运算符。

如碰到其他的问题 可以私下我 一起探讨学习

如果对你有所帮助还请 点赞 收藏谢谢~!

关注收藏博客 作者会持续更新...

相关推荐
ywf12158 分钟前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
恋猫de小郭15 分钟前
2026,Android Compose 终于支持 Hot Reload 了,但是收费
android·前端·flutter
hpoenixf6 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特6 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷7 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
mengchanmian7 小时前
前端node常用配置
前端
华洛8 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq8 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A9 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常9 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端