从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 添加了一条首页的面包屑,使用的三点运算符。

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

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

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

相关推荐
不一样的少年_3 分钟前
老板问我:AI真能一键画广州旅游路线图?我用 MCP 现场开图
前端·人工智能·后端
东方石匠3 分钟前
Javascript常见面试题
前端·javascript·面试
恋猫de小郭5 分钟前
Flutter 也有类 React Flow 的节点流程编辑器,快来了解下刚刚开源的 vyuh_node_flow
android·前端·flutter
性野喜悲6 分钟前
<script setup lang=“ts“>+uniapp实现轮播(swiper)效果
前端·javascript·vue.js·小程序·uni-app
wangdaoyin201013 分钟前
UniApp 在手机端(Android)打开选择文件和文件写入
android·前端·uni-app
用户4973573379818 分钟前
高端Web全栈工程师精品就业实战班课程 从零打造Web架构师
前端
我们没有完整的家25 分钟前
技术速递|Playwright MCP 调试 Web 应用时,GitHub Copilot 生成断言脚本的实用方法
前端·github·copilot
universe_0130 分钟前
前端学习之八股和算法
前端·学习
一川_39 分钟前
ElementUI分页器page-size切换策略:从保持当前页到智能计算的优化实践
前端
敲敲了个代码1 小时前
[特殊字符] Web 字体裁剪优化实践:把 42MB 字体包瘦到 1.6MB
前端·javascript·学习·html·web