上一篇我们集成项目所需要的插件,在整个main.ts里的结构都抽离到了各自相应的文件中,使整体main的结构看起来更加简介明了。今天我们讲下项目页面的布局
分析我们页面的布局,主要是比较常见的左右结构布局,这在后台管理系统中是很常见的布局。当然也有其他的布局,在我们这次的项目里没有其它类型,但你可以自己添加,这里提供一种思路
<template>
<component :is="components[layout]" />
template>
<script setup lang="ts">
import { computed } from "vue";
import { useThemeStore } from "@/stores/modules/theme";
import mode1 from "xxx.vue"; // 布局模式1
import mode2 from "xxx.vue"; // 布局模式2
import mode2 from "xxx.vue"; // 布局模式3
const components = {
mode1: mode1,
mode2: mode2,
mode3: mode3,
};
const themeStore = useThemeStore();
const layout = computed(() => themeStore.layout);
script>
下面我们说下本项目具体的布局方式
<template>
<el-container class="h-full" ref="appWrapperRef">
<AppMask v-show="showAppMask" @click="closeAppMask" />
<Asider />
<el-container direction="vertical" class="relative">
<Header />
<NavTab />
<Main />
<AppSetting />
el-container>
el-container>
template>
Asider主要有两个组件,分别是Logo组件和Menu组件,Logo就放个文本和图片通过Store控制表现形式就可以了,主要讲下Menu组件
在Menu组件外部需要包裹一个el-scrollbar
组件,通过这个组件可以让menu过多时产生滑动效果,里面内部放置一个menuItem
组件,注意组件拆分,方便维护。
在menu组件中,我们主要把一些不太常用的属性功能交给全局Store去配置,对于默认激活项这里采用useRouter
获取当前路由的path,点击事件使用select
事件,可以通过回调拿到menuItem
的index,这里我们通过一个正则判断/http(s)?:/.test(key)
判断是否是外链链接,如果是通过window.open
跳转,如果不是通过router.push
跳转就行了
// menu
这里需要提醒一点,使用
el-icon
的setting图标,如果size设置大小为18,在浏览器下会出现卡段,所以这里我们直接设置size大小19避开它。这里的Icon是自己的封装组件,后面会详细介绍
// menuItem
{{ $t(menu.title) }}
{{ $t(menu.title) }}
header比较简单我们就不说了,navTab组件有几种方式实现,可以使用el-scrollbar
配置滑动
自行实现,还有一种就是借助element的el-tabs
首先获取本地缓存的tab属性值,如果没有,从router获取路由传递给filterAffixTags
方法进行过滤,拿到meta属性里affix
initTabs & addTab
route.fullPath
,如果发生变化触发addTab
,内部可以对已存在的tag进行判断,这样可以保证刷新页面或者切换菜单自动增加tab// index.ts
// 初始化tabs
const router = useRouter();
const initTabs = () => {
const routes = router.getRoutes();
const tabs = storage.get('navTab') ?? filterAffixTags(routes);
for (const tab of tabs) {
navTabStore.add(tab);
}
};
// 添加tab
const addTab = () => {
const tab = {
fullPath: route.fullPath,
title: route.meta.title,
affix: route.meta.affix || false,
icon: route.meta.icon
};
navTabStore.add(tab);
};
// 切换tab
const handleChange = (fullPath: TabPaneName) => {
router.push(fullPath as string);
resetMenuStatus();
};
// 删除tab
const handleRemove = (fullPath: TabPaneName) => {
navTabStore.closeCurrent(fullPath as string);
};
onMounted(() => {
initTabs();
addTab();
});
watch(
() => route.fullPath,
() => {
addTab();
}
);
// ./helper.ts
// 过滤固定页签
import { RouteRecordRaw } from 'vue-router';
export const filterAffixTags = (routes: RouteRecordRaw[]) => {
const tags: App.TabsView[] = [];
routes.forEach((route: RouteRecordRaw) => {
if (route.meta?.affix) {
tags.push({
title: route.meta?.title,
fullPath: route.path,
icon: route.meta?.icon,
affix: route.meta?.affix
});
}
});
return tags;
};
@contextmenu.prevent
检测右键事件transition
在切换时做下动画//右键事件
//打开ul列表显示,通过传入的affix和fullPath控制ul列表的显示隐藏和禁用状态,
调整ul的left和top属性防止溢出
const handleContextMenu = (e: any, fullPath: string, affix?: boolean) => {
showFilterMenu(fullPath, affix); //筛选显示的右键菜单
const menuMinWidth = 105;
const offsetLeft = navTabRef.value.getBoundingClientRect().left; // container margin left
const offsetWidth = navTabRef.value.offsetWidth; // container width
const maxLeft = offsetWidth - menuMinWidth; // left boundary
const left = e.clientX - offsetLeft + 15; // 15: margin right
contextmenuLeft.value = left > maxLeft ? maxLeft : left;
contextmenuTop.value = e.clientY;
contextmenuVisible.value = true;
};
el-main
配置一下背景颜色,我们项目的页面基础颜色全部采用它的颜色el-scrollbar
router-view
使用配置缺口路由keep-alive
缓存页面对于缓存在vue里实现比react简单,但是如果路由是嵌套状态的情况下,配置根路由的缓存对子路由是不起作用的,我们需要在子路由下配置缓存状态,或者还有一种方法,可以结合beforeEach路由钩子在这里将路由缓存到store里
<template>
<el-main class="mt-1px !p-0 bg-[var(--el-bg-color-page)]">
<el-scrollbar>
<div class="p-3 h-full">
<router-view>
<template #default="{ Component, route }">
<el-backtop title="回到顶部" target=".el-main .el-scrollbar__wrap" />
<transition :name="themeStore.animateMode" mode="out-in" appear>
<keep-alive :include="routeStore.cacheList">
<component :is="Component" :key="route.fullPath" v-if="appStore.reloadFlag" />
keep-alive>
transition>
template>
router-view>
div>
el-scrollbar>
el-main>
template>
本文项目地址:Element-Admin