前端框架搭建(九)搭建页面布局框架【vite】

news/2024/11/9 4:44:37/

1.创建目录

  • BasicLayout——全局布局

  • components——布局组件

    • GlobalContent:全局内容
    • GlobalHeader:全局头部页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sS27aM4E-1672640417261)(assets/image-20230102123323-wfk5e4g.png)]

2.处理GlobalHeader

创建HeaderMenu——头部菜单

声明相关类型

typings目录下创建system.d.ts

  declare namespace App {/** 全局头部属性 */interface GlobalHeaderProps {/** 显示logo */showLogo: boolean;/** 显示头部菜单 */showHeaderMenu: boolean;/** 显示菜单折叠按钮 */showMenuCollapse: boolean;}/** 菜单项配置 */type GlobalMenuOption = import('naive-ui').MenuOption & {key: string;label: string;routeName: string;routePath: string;icon?: () => import('vue').VNodeChild;children?: GlobalMenuOption[];};/** 面包屑 */type GlobalBreadcrumb = import('naive-ui').DropdownOption & {key: string;label: string;disabled: boolean;routeName: string;hasChildren: boolean;children?: GlobalBreadcrumb[];};/** 多页签Tab的路由 */interface GlobalTabRouteextends Pick<import('vue-router').RouteLocationNormalizedLoaded, 'name' | 'fullPath' | 'meta'> {/** 滚动的位置 */scrollPosition: {left: number;top: number;};}interface MessageTab {/** tab的key */key: number;/** tab名称 */name: string;/** badge类型 */badgeProps?: import('naive-ui').BadgeProps;/** 消息数据 */list: MessageList[];}interface MessageList {/** 数据唯一值 */id: number;/** 头像 */avatar?: string;/** 消息icon */icon?: string;svgIcon?: string;/** 消息标题 */title: string;/** 消息发送时间 */date?: string;/** 消息是否已读 */isRead?: boolean;/** 消息描述 */description?: string;/** 标签名称 */tagTitle?: string;/** 标签props */tagProps?: import('naive-ui').TagProps;}}

配置路由相关状态管理

    import {  constRouter } from '@/router';import { defineStore } from 'pinia';
import { computed } from 'vue';
import { useRoute } from 'vue-router';interface RouteState {/** 菜单 */menus: App.GlobalMenuOption[];}export const useRouteStore = defineStore('route-store', {state:():RouteState => ({menus:[],}),actions:{transformRouteToMenu(){let menu:App.GlobalMenuOption[] = [] ;constRouter.forEach(route => {const{name , path} = routeconst menuItem : App.GlobalMenuOption = {key:path,label:String(name)}if(path != '/'){menu.push(menuItem);}})return menu},getRoute(){(this.menus as App.GlobalMenuOption[]) = this.transformRouteToMenu();},isLogin(){const route = useRoute();const isLogin = computed(() => route.fullPath === '/')return isLogin.value}}});

添加路由守卫

router->guard下创建dynamic.ts

import type { Router, RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
import { useRouteStore } from '@/store';/*** 动态路由*/
export async function createDynamicRouteGuard(to: RouteLocationNormalized,_from: RouteLocationNormalized,next: NavigationGuardNext,router: Router
) {const route = useRouteStore();await route.getRoute();next()}

修改路由配置

修改路由守卫的简单next

import type { Router } from 'vue-router';
import { useTitle } from '@vueuse/core';
import { createDynamicRouteGuard } from './dynamic';/*** 路由守卫函数* @param router - 路由实例*/
export function createRouterGuard(router: Router) {router.beforeEach(async (to, from, next) => {// 开始 loadingBarwindow.$loadingBar?.start();// 页面跳转权限处理createDynamicRouteGuard(to, from, next, router)});router.afterEach(to => {// 设置document titleuseTitle(to.name);// 结束 loadingBarwindow.$loadingBar?.finish();});
}

创建HeaderMenu组件

<template><div class="flex-1-hidden h-full px-10px"><n-scrollbar :x-scrollable="true" class="flex-1-hidden h-full" content-class="h-full"><div class="flex-y-center h-full"><n-menu:value="activeKey"mode="horizontal":options="menus"@update:value="handleUpdateMenu"/></div></n-scrollbar></div>
</template><script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import type { MenuOption } from 'naive-ui';
import { useRouteStore } from '@/store';
import { useRouterPush } from '@/utils/composables/router';const route = useRoute();
const routeStore = useRouteStore();
const { routerPush } = useRouterPush();const menus = computed(() => routeStore.menus as App.GlobalMenuOption[]);
const activeKey = computed(() => route.name as string);function handleUpdateMenu(_key: string, item: MenuOption) {const menuItem = item as App.GlobalMenuOption;routerPush(menuItem.key);
}
</script><style scoped>
:deep(.n-menu-item-content-header) {overflow: inherit !important;
}
</style>

创建index.ts导出

import HeaderMenu from './HeaderMenu.vue';export{HeaderMenu,
} 

创建GlobalHeader

<template><div class="flex-1-hidden flex-y-center h-full"><header-menu /></div></template><script setup lang="ts">import {HeaderMenu,} from './components';</script><style scoped>.global-header {box-shadow: 0 1px 2px rgb(0 21 41 / 8%);}</style>

3.全局布局组件

BasicLayout目录下创建简单布局组件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZsE4Spu-1672640417263)(assets/image-20230102135018-jxl8420.png)]

LayoutHeader

<template><header class="job-collect_header" :style="style"><slot></slot></header>
</template><script setup lang='ts'>
import { computed } from 'vue';interface Props {/** 开启fixed布局 */fixed?: boolean,/** fixed布局的层级 */zIndex?: number,/** 最小宽度 */minWidth?: number,/** 高度 */height?: number,/** 左侧内边距 */paddingLeft?: number,/** 动画过渡时间 */transitionDuration?: number,/** 动画过渡函数 */transitionTimingFunction?: string,
}const props = withDefaults(defineProps<Props>(), {fixed: true,zIndex: 1001,minWidth: 900,height: 56,paddingLeft: 0,transitionDuration: 300,transitionTimingFunction: 'ease-in-out',
})const style = computed(() => {const {fixed,zIndex,minWidth,height,paddingLeft,transitionDuration,transitionTimingFunction,} = propsconst position = fixed ? 'fixed' : 'staic';return `position:${position};z-index:${zIndex};min-width:${minWidth}px;height:${height}px;padding-left:${paddingLeft}px;transition-duration:${transitionDuration};transition-timing-function:${transitionTimingFunction};`
})</script><style scoped>
.job-collect_header {left: 0;top: 0;flex-shrink: 0;width: 100%;transition-property: padding-left;
}
</style>

LayoutMain

<template><main class="job-collect_main" :style="style"><slot></slot></main>
</template><script setup lang="ts">
import { computed } from "vue";interface Props {/** 顶部内边距 与 头部高度一致 */paddingTop?: number;/** 底部内边距 */paddingBottom?: number;/** 左侧内边距 */paddingLeft?: number;/** 动画过渡时间 */transitionDuration?: number;/** 动画过渡函数 */transitionTimingFunction?: string;
}const props = withDefaults(defineProps<Props>(), {paddingTop: 56,paddingBottom: 0,paddingLeft: 0,transitionDuration: 300,transitionTimingFunction: "ease-in-out",
});const style = computed(() => {const {paddingTop,paddingBottom,paddingLeft,transitionDuration,transitionTimingFunction,} = props;return `padding-top:${paddingTop}px;padding-bottom:${paddingBottom}px;padding-left:${paddingLeft}px;transition-duration:${transitionDuration};transition-timing-function:${transitionTimingFunction}`;
});
</script><style scoped>
.job-collect_main {flex-grow: 1;width: 100%;
}
</style>

layout组件

仅针对login不显示menu

<template><div class="job-collect" :style="{ minWidth: minWidth + 'px' }"><layout-header:padding-left="headerPaddingLeft"v-if="paddingTop"><slot name="header"></slot></layout-header><layout-content :padding-left="mainPaddingLeft" :padding-top="paddingTop"><slot></slot></layout-content></div>
</template><script setup lang="ts">
import { useRouteStore } from "@/store";
import { computed } from "vue";
import { LayoutHeader, LayoutContent } from "./";const route = useRouteStore()const isLogin = computed(() => route.isLogin)const paddingTop = computed(() => {if(isLogin.value()){return 0}return 56
})interface Props {/** 最小宽度 */minWidth?: number;/** 头部偏移左侧高度 */headerPaddingLeft?:number,/** 左侧头部高度 */siderPaddingTop?:number/** main左侧偏移 */mainPaddingLeft?:number/** 侧边可见 */siderVisible?: boolean;
}withDefaults(defineProps<Props>(), {minWidth: 900,headerPaddingLeft: 0,siderPaddingTop: 56,siderVisible: false,
});</script><style scoped>
.job-collect {display: flex;flex-direction: column;width: 100%;height: 100%;
}
</style>

全局布局组件

<template><admin-layout><template #header><global-header /></template><global-content /></admin-layout></template><script setup lang="ts">import AdminLayout from './components/layout.vue';import {GlobalContent,GlobalHeader,} from '../components';
</script><style scoped></style>

测试

请添加图片描述


http://www.ppmy.cn/news/8977.html

相关文章

(一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>

一、工作环境及项目简介 立创EDA&#xff1a;硬件原理图及PCB绘制。 全志F1C200S&#xff1a;F1C100S内置32MB DDR1内存&#xff0c;F1C200S内置64MB DDR1内存。 原理图&#xff1a;参考开源项目&#xff0c;详见墨云&#xff0c; 详见peng-zhihui。 核心板&#xff1a;四层…

【华为OD机试真题2023 JAVA】寻找关键钥匙

华为OD机试真题,2023年度机试题库全覆盖,刷题指南点这里 寻找关键钥匙 知识点字符串编程基础正则表达式排序 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 小强正在参加《密室逃生》游戏,当前关卡要求找到符合给定 密码K(升序的不重复小写字母组成)的箱子,并…

BEV视觉3D感知算法梳理

1. 基于BEV空间的自动驾驶感知任务 最近&#xff0c;基于BEV空间下的感知任务已经涌现出了众多优秀算法&#xff0c;并在多个自动驾驶公开数据集&#xff08;KITTI&#xff0c;Waymo&#xff0c;nuScenes&#xff09;上取得了非常不错的成绩。根据自动驾驶汽车上安装的传感器类…

自动驾驶专题介绍 ———— 摄像头

文章目录介绍工作原理实现功能分类按通信协议区分按不同感光芯片按像元排列方式介绍 摄像头可以采集汽车周边的图像信息&#xff0c;跟人类的眼睛最为接近。摄像头可以拥有较广的视场角、较大的分辨率&#xff0c;还可以提供颜色和纹理等信息。这些信息对于实现自动驾驶功能是存…

软件测试[用例篇]

一. 回顾测试用例 1.测试用例基本要素 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合。 这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 2.测试用例好处 测试用例可以提高测试效率&#xff08;可以减…

Docker简介

Docker官网链接&#xff1a; http://docker.p2hp.com/问题&#xff1a;我们开发的嵌入式项目基本是基于虚拟机下的ubuntu的&#xff0c;如果每一个项目要求的系统版本、库版本、交叉编译工具链等不一样&#xff0c;我们就需要为每一个项目安装一个对应的ubuntu&#xff0c;这既…

linphone android sdk 源码下载编译

前言 前面的有写过Android 使用Linphone SDK开发SIP客户端相关的文章, 在后续的开发过程中, 为了更深入了解linphone, 便尝试下载SDK源码自行编译. 关于linphone这里不作过多介绍, 可以参考前面的文章. Linphone-SDK 是一个将 Liblinphone 及其依赖项捆绑为 git 子模块的项目&a…

c++动态内存管理

1.回顾c语言中的动态内存管理 在c语言中&#xff0c;我们想要动态开辟一段空间&#xff0c;需要使用malloc&#xff0c;calloc&#xff0c;realloc几个函数 void* malloc (size_t size); //在堆上申请size个字节的空间void* calloc (size_t num, size_t size); //第一个参数是…