Layout布局
一、背景与问题
很多框架都有多种布局形态,即 菜单在左侧、顶部;菜单是展开形态、菜单是传统折叠菜单 等等,但是呢,很多框架layout这块封装的就特别复杂,事情为什么变得复杂呢,想有以下几个原因:
- 1、多种布局相同的组件很多,所以会抽象的组件较多
- 2、因为要提供配置页面,所以布局要和状态管理vuex挂钩
- 3、多种布局,大部分是layout的位置(即layout组件的属性变化)
- 4、炫技各种抽象 or 不炫技代码堆积到了一起
以上的以上,很多写的就很复杂,一个layout文件弄几千行,或者超级多的变量,不敢想象
二、架构思想
1) layout 种类大概就3,4中,索性就为每个layout 设计一个 layout.vue文件,作为入口就可以了 2) 对于大类的公共组件,抽出来放到 layout/components
中 3) 对于多个layout中相同代码,不再抽象,保持独立,给予最大的扩展性
以上三点虽然 可能会有相同的代码,但是并不会太多,好处是 大大的降低了复杂度,提高的阅读性和维护性。
这也是可以满足的好的代码原则的。好的代码
1)满足业务需要:代码是来实现业务的,如果业务都实现不了,代码也就没什么价值了
2)代码尽可能的清晰明了:就是让小白也能看懂你的代码
3)代码尽可能的少:在保证清晰明了的前提下,能少一行少一行,能少一个类少一个类,能少一行注释少一行注释
4)代码尽可能复用性和模块化:在保证清晰明了和尽可能少的前提下,能复用的代码尽量复用,能模块的尽量模块
三、具体实现
目录结构如下:
js
| layout / 布局目录
| --- index.vue 引入文件(在这里vuex判断是哪种具体的layout)
| --- side-layout.vue 传统菜单布局layout
| --- side-expand-layout.vue 展开菜单布局layout
| --- top-layout.vue 顶部菜单布局layout
| --- components/ 公共组件
在 index.vue
中代码, 使用if 直接判断是哪一种类型的 layout,很清晰
vue
<template>
<!--左侧菜单 模式-->
<SideLayout v-if="layout === LAYOUT_ENUM.SIDE.value" />
<!--左侧展开菜单 模式-->
<SideExpandLayout v-if="layout === LAYOUT_ENUM.SIDE_EXPAND.value" />
<!--顶部菜单 模式-->
<TopLayout v-if="layout === LAYOUT_ENUM.TOP.value" />
</template>
<script setup>
import { computed } from 'vue';
import { LAYOUT_ENUM } from '/@/constants/layout-const';
import SideExpandLayout from './side-expand-layout.vue';
import SideLayout from './side-layout.vue';
import TopLayout from './top-layout.vue';
import { useAppConfigStore } from '/@/store/modules/system/app-config';
const layout = computed(() => useAppConfigStore().$state.layout);
</script>
传统菜单layout,side-layout.vue
中
vue
<template>
<a-layout class="admin-layout" style="min-height: 100%">
<!-- 侧边菜单 side-menu -->
<a-layout-sider class="side-menu" :width="sideMenuWidth" :collapsed="collapsed" :theme="theme">
<!-- 左侧菜单 -->
<SideMenu :collapsed="collapsed" />
</a-layout-sider>
<!--中间内容,一共三部分:1、顶部;2、中间内容区域;3、底部(一般是公司版权信息);-->
<a-layout id="smartAdminMain" :style="`height: ${windowHeight}px`" class="admin-layout-main">
<!-- 顶部头部信息 -->
<a-layout-header class="layout-header">
<a-row class="layout-header-user" justify="space-between">
<a-col class="layout-header-left">
<!-- 菜单收缩 -->
<span class="collapsed-button">
<menu-unfold-outlined v-if="collapsed" class="trigger" @click="() => (collapsed = !collapsed)" />
<menu-fold-outlined v-else class="trigger" @click="() => (collapsed = !collapsed)" />
</span>
<!-- 首页 按钮 -->
<a-tooltip placement="bottom">
<template #title>首页</template>
<span class="home-button" @click="goHome">
<home-outlined class="trigger" />
</span>
</a-tooltip>
<!-- 面包屑 -->
<span class="location-breadcrumb">
<MenuLocationBreadcrumb />
</span>
</a-col>
<!---用戶操作区域:搜索、消息、国际化、的-->
<a-col class="layout-header-right">
<HeaderUserSpace />
</a-col>
</a-row>
<PageTag />
</a-layout-header>
<!--中间内容-->
<a-layout-content id="smartAdminLayoutContent" class="admin-layout-content">
<!--不keepAlive的iframe使用单个iframe组件-->
<IframeIndex v-if="iframeNotKeepAlivePageFlag" :key="route.name" :name="route.name" :url="route.meta.frameUrl" />
<!--keepAlive的iframe 每个页面一个iframe组件-->
<IframeIndex
v-for="item in keepAliveIframePages"
v-show="route.name == item.name"
:key="item.name"
:name="item.name"
:url="item.meta.frameUrl"
/>
<!--非iframe使用router-view-->
<div v-show="!iframeNotKeepAlivePageFlag && keepAliveIframePages.every((e) => route.name != e.name)">
<router-view v-slot="{ Component }">
<keep-alive :include="keepAliveIncludes">
<component :is="Component" :key="route.name" />
</keep-alive>
</router-view>
</div>
</a-layout-content>
<!-- footer 版权公司信息 -->
<a-layout-footer class="layout-footer" v-show="footerFlag">
<smart-footer />
</a-layout-footer>
<!--- 回到顶部 -->
<a-back-top :target="backTopTarget" :visibilityHeight="80" />
</a-layout>
<!-- 右侧帮助文档 help-doc -->
<a-layout-sider v-show="helpDocFlag" theme="light" :width="180" class="help-doc-sider" :trigger="null" style="min-height: 100%">
<SideHelpDoc />
</a-layout-sider>
</a-layout>
</template>
<script setup>
import 具体的导入;
//菜单宽度
const sideMenuWidth = computed(() => useAppConfigStore().$state.sideMenuWidth);
//主题颜色
const theme = computed(() => useAppConfigStore().$state.sideMenuTheme);
//是否显示标签页
const pageTagFlag = computed(() => useAppConfigStore().$state.pageTagFlag);
// 是否显示帮助文档
const helpDocFlag = computed(() => useAppConfigStore().$state.helpDocFlag);
// 是否显示页脚
const footerFlag = computed(() => useAppConfigStore().$state.footerFlag);
//是否隐藏菜单
const collapsed = ref(false);
//页面初始化的时候加载水印
onMounted(() => {
watermark.set('smartAdminLayoutContent', useUserStore().actualName);
});
//回到顶部
const backTopTarget = () => {
return document.getElementById('smartAdminMain');
};
const router = useRouter();
function goHome() {
router.push({ name: HOME_PAGE_NAME });
}
const windowHeight = ref(window.innerHeight);
window.addEventListener('resize', function () {
windowHeight.value = window.innerHeight;
});
// ----------------------- keep-alive相关 -----------------------
let { route, keepAliveIncludes, iframeNotKeepAlivePageFlag, keepAliveIframePages } = smartKeepAlive();
</script>
展开菜单和顶部菜单,具体可见,具体请见
联系我们
1024创新实验室-主任:卓大,混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。
1024创新实验室 致力于成为中原领先、国内一流的技术团队, 以AI+数字化为驱动,用技术为产业互联网提供无限可能, 业务如下:
- 教育领域(高职院校数字化、就业创业大数据平台、继续教育平台;在线教育系统、视频直播、题库等,包含:医学、应急管理、成考、专升本等)
- 供应链领域(网络货运平台、大宗贸易进销存ERP、物流管理TMS、B2B电商、仓储WMS、AI提效等)
- 中医领域(诊所数字化管理、互联网医院、AI辅助诊疗、中医适宜技术、在线云问诊、空中药房等)
- AI+软件领域(软件定制外包、开源技术、数据大屏、国产化改造、技术升级换代、人员外包、技术顾问、技术培训等)
加微信: 卓大 拉你入群,一起学习 | 公众号 :六边形工程师 分享:赚钱、代码、生活 | 请 “1024创新实验室” 烩面里加肉 咖啡配胡辣汤,提神又饱腹 | 抖音 : 六边形工程师 直播:赚钱、代码、中医 |