前端路由layout布局处理以及菜单交互(三)

上篇介绍了前端项目部署以及基本依赖的应用,这次主要对于路由以及布局进行模块化处理

一、 创建layout模块

在这里插入图片描述

1、新建src/layout/index.vue

<template><el-container class="common-layout"><!-- <el-aside class="aside"><Aside/></el-aside> --><el-container><el-header class="header"><Header/></el-header><el-main class="main"><router-view></router-view></el-main><el-footer class="footer">Copyright © 2020 云风网, All rights reserved.ICP20002789-1</el-footer></el-container></el-container>
</template><script setup lang="ts">
// import Aside from './components/aside.vue'
import Header from './components/header.vue'</script><style lang="scss" scoped>
@import '@/assets/styles/mixins.scss';
.common-layout{width: 100%;height: 100vh;.aside{height: 100vh;width: 200px;}.header{height: 60px;padding: 0;}.main{@include scrollBar;}.footer{height: 60px;background-color: #343a40;color: #fff;line-height: 60px;}
}</style>

2、新建头部组件src/layout/components/header.vue

<template><el-menu:default-active="activeIndex"class="header-container"mode="horizontal":ellipsis="false"@select="handleSelect"><el-menu-item index="0"><imgclass="logo"src="@/assets/logo.svg"alt="logo"/></el-menu-item><navbar-itemv-for="(route, index) in routerList":key="route.path + index":item="route":base-path="route.path":is-nest="false"/></el-menu>
</template><script setup lang="ts">
import NavbarItem from './navbarItem.vue';
import { useRouter} from 'vue-router';
const router = useRouter();const activeIndex = ref('1')
const routerList = router.getRoutes();
console.log('routerList',routerList);
const handleSelect = (key: string, keyPath: string[]) => {console.log(key, keyPath)
}
</script><style lang="scss" scoped>
.el-menu--horizontal > .el-menu-item:nth-child(1) {margin-right: auto;
}
.header-container{height: 100%;padding: 0 50px;background-color: #fff;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);.logo{width: 40px;}
}
</style> 

3、新建菜单组件src/layout/components/navbarItem.vue

<template><div v-if="!item.hidden"><template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren)"><app-link v-if="onlyOneChild.meta.title" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)"><el-menu-item :index="resolvePath(onlyOneChild.path,'')" @click="handleClick(item.path)"><svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" /><template #title><span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span></template></el-menu-item></app-link></template><el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path,'')" teleported><template v-if="item.meta" #title><svg-icon :icon-class="item.meta && item.meta.icon" /><span class="menu-title" :title="hasTitle(item.meta.title)">{{ item.meta.title }}</span></template><app-link v-for="child in item.children" :key="child.path"  :to="resolvePath(child.path, '')"><el-menu-item:item="child"class="nest-menu"@click="handleClick(child.path)"><template #title><span class="menu-title">{{ child.meta.title }}</span></template></el-menu-item></app-link></el-sub-menu></div></template><script setup lang="ts">import { isExternal } from '@/utils/validate.ts'import AppLink from './Link.vue'import { getNormalPath } from '@/utils/mis'interface MenuItem {path: string;meta?: {icon?: string;title?: string;[key: string]: any;};query?: string;children?: MenuItem[];hidden?: boolean;noShowingChildren?: boolean;}const props = defineProps<{item: MenuItem;isNest: boolean;basePath: string;}>();const onlyOneChild = ref<MenuItem>({ path: '', meta: {} });function hasOneShowingChild(children: MenuItem[] = [], parent: MenuItem): boolean {const showingChildren = children.filter(item => {if (item.hidden) {return false;} else {onlyOneChild.value = item;return true;}});if (showingChildren.length === 1) {return true;}if (showingChildren.length === 0) {onlyOneChild.value = { ...parent, path: '', noShowingChildren: true, meta: {} };return true;}return false;}function handleClick(routePath: string) {localStorage.setItem('routePath', routePath);}function resolvePath(routePath: string, routeQuery?: string) {if (isExternal(routePath)) {return routePath;}if (isExternal(props.basePath)) {return props.basePath;}if (routeQuery) {let query = JSON.parse(routeQuery);return { path: getNormalPath(`${props.basePath}/${routePath}`), query };}return getNormalPath(`${props.basePath}/${routePath}`);}function hasTitle(title: string | undefined): string {return title && title.length > 5 ? title : '';}</script>

4、新建菜单组件src/layout/components/Link.vue

<template><component :is="type" v-bind="linkProps()"><slot /></component>
</template><script setup lang="ts">
import { isExternal } from '@/utils/validate.ts'const props = defineProps({to: {type: [String, Object],required: true}
})const isExt = computed(() => {return isExternal(props.to)
})const type = computed(() => {if (isExt.value) {return 'a'}return 'router-link'
})function linkProps() {if (isExt.value) {return {href: props.to,target: '_blank',rel: 'noopener'}}return {to: props.to}
}
</script>

5、新建方法封装文件src/utils/validate.ts

/*** 判断url是否是http或https * @param {string} path* @returns {Boolean}*/export function isHttp(url) {return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
}/*** 判断path是否为外链* @param {string} path* @returns {Boolean}*/export function isExternal(path) {return /^(https?:|mailto:|tel:)/.test(path)
}/*** @param {string} str* @returns {Boolean}*/
export function validUsername(str) {const valid_map = ['admin', 'editor']return valid_map.indexOf(str.trim()) >= 0
}/*** @param {string} url* @returns {Boolean}*/
export function validURL(url) {const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/return reg.test(url)
}/*** @param {string} str* @returns {Boolean}*/
export function validLowerCase(str) {const reg = /^[a-z]+$/return reg.test(str)
}/*** @param {string} str* @returns {Boolean}*/
export function validUpperCase(str) {const reg = /^[A-Z]+$/return reg.test(str)
}/*** @param {string} str* @returns {Boolean}*/
export function validAlphabets(str) {const reg = /^[A-Za-z]+$/return reg.test(str)
}/*** @param {string} email* @returns {Boolean}*/
export function validEmail(email) {const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/return reg.test(email)
}/*** @param {string} str* @returns {Boolean}*/
export function isString(str) {if (typeof str === 'string' || str instanceof String) {return true}return false
}/*** @param {Array} arg* @returns {Boolean}*/
export function isArray(arg) {if (typeof Array.isArray === 'undefined') {return Object.prototype.toString.call(arg) === '[object Array]'}return Array.isArray(arg)
}

二、修改router/index.ts

import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/layout/index.vue'
//公共路由
export const constantRoutes = [{path: '/',component: Layout,redirect: '/home',hidden: false,children: [{path: 'home',name: 'Home',meta:{ title: '系统知识',routerNum: 0},component: () => import('@/views/Home.vue')}]},{path: '/',redirect: "/article",component: Layout,hidden: false,children: [{path: 'article',name: 'Article',meta:{ title: '插件管理',routerNum: 1},component: () => import('@/views/Article.vue')}]},{path: '/',redirect: "/mix",component: Layout,hidden: false,meta:{ title: '多级菜单',routerNum: 0},children: [{path: 'home',name: 'Home',meta:{ title: '系统知识',routerNum: 0},component: () => import('@/views/Home.vue')},{path: 'article',name: 'Article',meta:{ title: '插件管理',routerNum: 1},component: () => import('@/views/Article.vue')}]},// {//     path: '/article/:id',//     name: 'Article',//     meta:{ title: '插件管理',routerNum: 1},//     component: () => import('@/views/Article.vue')// }
]
const router = createRouter({history: createWebHistory(),routes: constantRoutes
})export default router 

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/65232.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot(4)使用 IDEA 搭建 Spring Boot+MyBatis 项目全流程实战

文章目录 一、⚡搞个引言二、⚡开始搭建 Spring Boot 项目吧&#xff01;2.1 启动 IDEA 并创建新项目2.2 选择项目依赖2.3 完成项目创建 三、&#x1f4d8;项目结构剖析四、✍配置数据库连接五、✍ 创建 MyBatis 相关组件5.1 实体类&#xff08;Entity&#xff09;5.2 Mapper 接…

使用wujie搭建微前端应用及踩坑

线上演示地址&#xff1a;wujie-app 源码地址&#xff1a;https://github.com/Jiang-K-J/micro-app?tabreadme-ov-file &#xff08;如果觉您得有用&#xff0c;请帮忙点个小星星&#xff09; 主应用&#xff1a;vue2webpack 子应用&#xff1a;vue3vite 子应用&#xff1…

【数据可视化-11】全国大学数据可视化分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

141.《mac m1安装mongodb详细教程》

文章目录 下载从官网下载安装包 下载后双击解压出文件夹安装文件名修改为 mongodb配置data存放位置和日志log的存放位置启动方式一方式二方式二:输入mongo报错以及解决办法 本人电脑 m2 pro,属于 arm 架构 下载 官网地址: mongodb官网 怎么查看自己电脑应该下载哪个版本,输入…

frameworks 之 Winscope 工具

frameworks 之 Winscope 工具 1. 手机端开启2. 加载追踪的文件2.1 Android12 3. 分析文件 Winscope 是一款 Web 工具&#xff0c;可以让用户在动画和转换期间和之后记录、重放和分析多个系统服务的状态。Winscope 将所有相关的系统服务状态记录在一个跟踪文件中。使用带有跟踪文…

在日期字段中自动插入斜杠“/”的最佳方法是什么

我正在尝试向输入日期字段添加功能&#xff0c;以便当用户输入数字时&#xff0c;自动添加斜杠“/”。 所以假设我有以下 html&#xff1a; <input type"text" id"fooDate" />假设我有以下 javascript&#xff1a; var dateField document.getElem…

极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现

极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现 目录 极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现1. 极限学习机 (ELM) 算法概述1.1 单隐层前馈神经网络1.2 ELM的优势2. ELM的核心技术2.1 模型定义2.2 随机初始化2.3 最小二乘法2.4…

【姿态估计实战】使用OpenCV和Mediapipe构建锻炼跟踪器【附完整源码与详细说明】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

nvm如何安装

一、简介 在实际的开发和学习中可能会遇到不同项目的 node 版本不同&#xff0c;而出现的兼容性问题。 而 nvm 就可以很好的解决这个问题&#xff0c;它可以在同一台机器上下管理多个 node 版本&#xff0c;使得程序员可以轻松地安装、卸载和切换不同的 node 版本。 在下载和配…

cityhash–对字符串的哈希算法

原文地址&#xff1a;cityhash–对字符串的哈希算法 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 分享一个给字符串计算hash的开源库&#xff0c;谷歌出品。 源代码在&#xff1a;https://github.com/google/cityhash 可以自己下载&#x…

spring cloud微服务分布式架构

spring cloud微服务分布式架构 应用架构 单体应用架构&#xff1a;all in one 如&#xff1a;前端后端部署在一台服务器中 web应用和数据库放在同一台服务器中&#xff0c;只要服务器挂掉&#xff0c;应用就会终止。 分布式架构&#xff1a;将一个系统拆分为多个独立的组件&…

【HarmonyOS】鸿蒙应用点9图的处理(draw9patch)

【HarmonyOS】鸿蒙应用点9图的处理&#xff08;draw9patch&#xff09; 一、前言&#xff1a; 首先在鸿蒙中是不支持安卓 .9图的图片直接使用。只有类似拉伸的处理方案&#xff0c;鸿蒙提供的Image组件有与点九图相同功能的API设置。 可以通过设置resizable属性来设置Resiza…

深入Android架构(从线程到AIDL)_12 Android UI 单线程程序

目录 6、 Android UI 单线程程序 單線程程序概念 单线程可避免线程安全问题 SurfaceView与非UI线程 6、 Android UI 单线程程序 單線程程序概念 单线程程序意谓着两个(或多个)线程不能共享对象或变量值。Android的UI是单线程程序的环境。UI控件(如Button等)都是由UI线程所…

STM32-笔记36-ADC(模拟/数字转换器)

一、什么是ADC&#xff1f; 全称&#xff1a;Analog-to-Digital Converter&#xff0c;指模拟/数字转换器。 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁。 12 位 ADC 是一种逐次逼近型模拟数字转换器&#xff08;0…

房产销售系统(源码+数据库+文档)

亲测完美运行带论文&#xff1a;文末获取源码 文章目录 项目简介&#xff08;论文摘要&#xff09;运行视频包含的文件列表&#xff08;含论文&#xff09;前端运行截图后端运行截图 项目简介&#xff08;论文摘要&#xff09; 随着科学技术的飞速发展&#xff0c;各行各业都在…

游戏社交趋势下,游戏语音再升级!

如今&#xff0c;游戏已成为我们社交生活的一个重要娱乐方式&#xff0c;春节临近&#xff0c;与亲朋好友一起畅玩“开黑”无疑是节假日的一大乐趣。在游戏社交互动中&#xff0c;“游戏语音”不可或缺。在传统游戏语音领域&#xff0c;多人在线游戏如 MOBA、FPS 和 MMORPG 的实…

HTML5实现好看的博客网站、通用大作业网页模板源码

HTML5实现好看的博客网站、通用大作业网页模板源码 前言一、设计来源1.1 主界面1.2 列表界面1.3 文章界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的博客网站、通用大作业网页模板源码&#xff0c;博客网站源码&#xff0c;HTML模板源码&#xff0…

ArcGIS中怎么把数据提取到指定范围(裁剪、掩膜提取)

最近&#xff0c;经常能收到怎么把数据提取到指定范围、栅格数据怎么裁剪、矢量数据怎么裁剪、栅格数据怎么掩膜提取的咨询。 下面是我对这个问题的解决思路&#xff1a; 对于矢量数据&#xff1a; ①首先把数据加载进来 ②软件界面上面的工具栏找到→地理处理→裁剪&#x…

PHP 使用集合 处理复杂数据 提升开发效率

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…

(转)rabbitmq怎么保证消息不丢失?

RabbitMQ 可以通过以下多种机制来保证消息不丢失&#xff1a; 生产阶段 - 持久化队列和交换器&#xff1a; - 在声明队列和交换器时&#xff0c;将 durable 参数设置为 true &#xff0c;确保它们是持久化的。这样&#xff0c;即使 RabbitMQ 节点重新启动&#xff0c;队列和交…