当前位置: 首页 > news >正文

vue3 学习笔记17 -- 基于el-menu封装菜单

vue3 学习笔记17 – 基于el-menu封装菜单

前提条件:组件创建完成

配置路由

// src/router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
export const Layout = () => import('@/layout/index.vue')
// 静态路由
export const routes: RouteRecordRaw[] = [{path: '/login',component: () => import('@/views/login/index.vue'),hidden: true},{path: '/401',component: () => import('@/views/error-page/401.vue'),hidden: true},{path: '/404',component: () => import('@/views/error-page/404.vue'),hidden: true},{path: '/',component: Layout,redirect: '/home',children: [{path: 'home',component: () => import('@/views/home/index.vue'),name: 'Home',meta: { title: '首页', icon: 'home' }}]},{path: '/permission',component: Layout,meta: {title: '权限管理',icon: 'permission'},children: [{path: 'user',component: () => import('@/views/permission/user/index.vue'),name: 'User',meta: { title: '用户管理'}},{path: 'role',component: () => import('@/views/permission/role/index.vue'),name: 'Role',meta: { title: '角色管理' }}]}
]
const router = createRouter({history: createWebHashHistory(),routes: routes as RouteRecordRaw[],scrollBehavior: () => ({ left: 0, top: 0 })
})
/*** 重置路由*/
export function resetRouter() {router.replace({ path: '/login' })
}export default router

封装el-menu

  • 目录结构
    在这里插入图片描述

  • sidebar/index.vue

<script lang="ts" setup>
// sidebarItem 项组件
import SideBarItem from './sidebarItem.vue'
import { useRouter } from 'vue-router'
import { usePermissionStoreHook } from '@/stores/permission'
import { toRaw } from 'vue'
// 拿到路由列表,过滤我们不想要的
const router = useRouter()
const permissionStore = usePermissionStoreHook()
const routerList = toRaw(permissionStore.permission.routes)
console.log(routerList, '获取到的路由list')
const defaultOpenList = []
const activeMenu = ref()
function handleSelect(index, indexPath) {console.log(index, indexPath)
}
watch(() => router.currentRoute.value.path,(toPath) => {activeMenu.value = toPath//要执行的方法console.log(toPath)},{ immediate: true, deep: true }
)
</script>
<template><div class="sidebar"><!-- 导航菜单 --><el-menuref="elMenu":default-active="activeMenu"@select="handleSelect":default-openeds="defaultOpenList"router><!-- 引入子组件 --><SideBarItem :routerList="routerList" /></el-menu></div>
</template>
<style lang="scss" scoped>
.sidebar {height: 100%;padding-top: 30px;:deep(.el-menu) {width: 100%;height: 100%;overflow-y: auto;background: transparent;border: none;.el-menu-item {font-size: 16px;height: 25px;padding: 0 30px;margin-bottom: 40px;background: transparent;display: flex;align-items: center;outline: none;box-sizing: border-box;&:last-child {margin-bottom: 0;}img {width: 24px;height: 24px;margin-right: 10px;}span {color: var(--vt-main-color);}&.is-active {position: relative;span {color: var(--vt-main-color);font-weight: 600;font-family: 'PingFangSC-Semibold';}&::after {content: '';position: absolute;width: 4px;height: 30px;background: #2b5ae8;left: 0;top: 0;bottom: 0;margin: auto;z-index: 999;}}}.el-sub-menu {font-size: 14px;margin-bottom: 40px;.el-menu-item {min-width: 179px;padding: 0 64px !important;outline: none;overflow: hidden;font-size: 14px;margin-bottom: 20px;&:last-child {margin-bottom: 0;}&:first-child {margin-top: 20px;}span {color: #797979;}&.is-active {span {font-family: 'PingFangSC-Semibold';font-weight: 600;color: var(--vt-main-color);}}}&.is-opened {.el-submenu__title {> span {color: var(--vt-main-color);}}&.is-active {.el-submenu__title {font-weight: 600;}}}.el-sub-menu__title {font-size: 16px;height: 25px;display: flex;align-items: center;padding: 0 30px !important;background: transparent;img {width: 24px;height: 24px;margin-right: 10px;}&:hover {background: transparent;}+ .el-menu {.el-submenu__title {background: transparent;padding: 0 64px !important;}.el-submenu {.el-menu {.el-menu-item {padding: 0 100px !important;&.is-active {padding: 0 100px !important;}}}}}// span {//   position: relative;//   &::after {//     content: '';//     @include imageURL('closeMenu.png');//     width: vw(5 * 2);//     height: vw(5 * 2);//     position: absolute;//     right: vw(-15 * 2);//     top: 0;//     bottom: 0;//     margin: auto;//   }// }}.el-sub-menu__icon-arrow {display: none;}&.is-opened {> .el-sub-menu__title {&:hover {background: transparent;}}.el-menu-item {padding: 0 64px !important;&.is-active {padding-left: 64px !important;font-weight: 600;color: var(--vt-main-color);}}}.el-submenu {margin-bottom: 20px;&:first-child {margin-top: 20px;}}}}
}
</style>
  • sidebar/siderbarItem.vue
<script lang="ts" setup>
defineProps({routerList: {type: Array,default: () => {return []}}
})
const getImageUrl = (iconName) => {return new URL(`../../../assets/menu/${iconName}.png`, import.meta.url).href
}
</script>
<template><template v-for="menu in routerList"><el-sub-menu:key="menu.url":index="menu.url"v-if="menu.children && menu.children.length > 0 && !menu.hidden"><template #title><img :src="getImageUrl(menu.meta.icon)" alt="" /><span class="menu-title">{{ menu.meta.title }}</span></template><sidebarItem :router-list="menu.children"></sidebarItem></el-sub-menu><el-menu-item :key="menu.meta.url + 'u'" :index="menu.meta.url" v-else-if="!menu.hidden"><img :src="getImageUrl(menu.meta.icon)" alt="" v-if="menu.meta.icon" /><span class="menu-title">{{ menu.meta.title }}</span></el-menu-item></template>
</template>
  • layout/index.vue – 引入菜单
<template><div class="page-box"><div class="page-left"><div class="logo-box"><img src="@/assets/menu/logo-word.png" alt="" /></div><sidebar class="side-menu"></sidebar></div><div class="page-right"><div class="header-box"><div class="title">让电看得见摸得着.</div></div><Layout></Layout></div></div>
</template>
<script setup lang="ts">
import Layout from './layout.vue'
import sidebar from './components/sidebar/index.vue'
</script>
<style lang="scss" scoped>
.page-box {width: 100%;height: 100%;display: flex;overflow: hidden;position: relative;background: #f0f0f0;.page-left {width: 258px;position: fixed;left: 6px;top: 0;bottom: 0;margin: auto;display: flex;flex-direction: column;background: #f0f0f0;.logo-box {height: 73px;display: flex;align-items: center;padding-left: 34px;width: 100%;img {width: 73px;height: 30px;}}.side-menu {width: 100%;flex: 1;background: url('@/assets/menu/bg.png') no-repeat;background-size: 100% 100%;overflow: hidden;transition: width 0.28s;margin-bottom: 60px;box-sizing: content-box;}}.page-right {flex: 1;height: 100%;transition: margin-left 0.28s;margin-left: 264px;display: flex;flex-direction: column;.header-box {position: fixed;width: 87.0625%;//210-230left: 260px;top: 0;padding: 0 50px;display: flex;align-items: center;height: 73px;justify-content: space-between;box-sizing: border-box;z-index: 9;}}
}
</style>
  • layout/lauout.vue
<template><div id="app-main"><router-view v-slot="{ Component, route }"><transition name="router-fade" mode="out-in"><div key="route.fullPath"><component :is="Component" /></div></transition></router-view></div>
</template>
<script setup lang="ts"></script>
<style lang="scss">
#app-main {flex: 1;height: 100%;padding-top: 73px;display: flex;-webkit-box-orient: vertical;-webkit-box-direction: normal;-ms-flex-direction: column;flex-direction: column;padding-left: 40px;
}
</style>
  • 运行项目查看页面

相关文章:

vue3 学习笔记17 -- 基于el-menu封装菜单

vue3 学习笔记17 – 基于el-menu封装菜单 前提条件&#xff1a;组件创建完成 配置路由 // src/router/index.ts import { createRouter, createWebHashHistory } from vue-router import type { RouteRecordRaw } from vue-router export const Layout () > import(/lay…...

使用 Redis 实现验证码、token 的存储,用自定义拦截器完成用户认证、并使用双重拦截器解决 token 刷新的问题

可以看一下我以前做过的笔记&#xff1a;黑马点评 短信登录部分 基于session实现登录流程 1.发送验证码 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验…...

反转链表 - 力扣(LeetCode)C语言

206. 反转链表 - 力扣&#xff08;LeetCode&#xff09;( 点击前面链接即可查看题目) /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* reverseList(struct ListNode* head) {if(head NULL)…...

【Linux】进程间通信(1):进程通信概念与匿名管道

人与人之间是如何通信的&#xff1f;举个简单的例子&#xff0c;假如我是月老&#xff0c;我要为素不相识的但又渴望爱情的男女两方牵红线。我需要收集男方的信息告诉女方&#xff0c;收集女方的信息告诉男方&#xff0c;然后由男女双方来决定是否继续。对于他们而言&#xff0…...

Spring从入门到精通 01

文章目录 1. 依赖注入 (Dependency Injection, DI)2. 面向切面编程 (Aspect-Oriented Programming, AOP)3. 事务管理4. 简化 JDBC 开发5. 集成各种框架和技术6. 模块化和扩展性&#xff1a;主要的 Spring 模块&#xff1a;Core Container&#xff1a;AOP 模块&#xff1a;Data …...

C语言经典习题25

冒泡排序 对一维数组进行升序排序&#xff0c;然后在数组中输入20个数&#xff0c;将排序后的结果打印输出。 #include<stdio.h> #define N 20 int main() {int a[N];int i;for(i0;i<N;i) //初始化数组的数 {scanf("%d",&a);}for(i0;…...

2-47 基于matlab的时域有限差分法(FDTD法)拉夫等效原理进行时谐场外推

基于matlab的时域有限差分法(FDTD法)拉夫等效原理进行时谐场外推。外推边界距离吸收边界的距离、电磁场循环、傅立叶变换提起幅值和相位、各远区剖分点电场、方向系数计算等操作&#xff0c;得出可视化结果。程序已调通&#xff0c;可直接运行。 2-47 时域有限差分法(FDTD法) 拉…...

JupyterNotebook快捷键 自用

COMMAND MODE —————————————————————————————— Up Down cells的上下选择 A B 在上/下方插入cell C V X 复制/粘贴/剪切cell 双击D 删除所选cell Z 恢复被删除的cell 双击I Interrupt中断内核 Shift Enter 运行cell并选择下方 EDIT MODE ———…...

【我的OpenGL学习进阶之旅】讲一讲GL_TEXTURE_2D和GL_TEXTURE_EXTERNAL_OES的区别

在使用OpenGL ES进行图形图像开发时,我们常使用GL_TEXTURE_2D纹理类型,它提供了对标准2D图像的处理能力。这种纹理类型适用于大多数场景,可以用于展示静态贴图、渲染2D图形和进行图像处理等操作。 另外,有时我们需要从Camera或外部视频源读取数据帧并进行处理。这时,我们…...

Makefile 如何将生成的 .o 文件放到指定文件夹

研究了不少文章&#xff0c;我行通了一个&#xff0c;但是也不全&#xff0c;目前只能适用当前文件夹&#xff0c;如果源文件有子文件夹处理不了&#xff0c;还得继续研究。很多人说编译完把O文件移动走或者直接删掉。我想说的是不符合我的要求&#xff0c;移走或者删除O文件&a…...

聊一聊知识图谱结合RAG

因为最近在做一些关于提高公司内部使用的聊天机器人的回答准确率&#xff0c;并且最近微软官方也是开源了一下graphrag的源码&#xff0c;所以想聊一聊这个知识图谱结合rag。 rag在利用私有数据增强大模型回答的领域是一种比较典型的技术&#xff0c;也就是我们提出问题的时候&…...

Java面试锦集 之 一、Java基础(1)

一、Java基础&#xff08;1&#xff09; 1.final 关键字的作用&#xff1f; 修饰变量&#xff1a; 一旦被赋值&#xff0c;就不能再被修改&#xff0c;保证了变量值的稳定性。 例&#xff1a; final int NUMBER 10; //之后就不能再改变 NUMBER 的值了。修饰方法&#xff1a;…...

【leetcode】排列序列

给出集合 [1,2,3,...,n]&#xff0c;其所有元素共有 n! 种排列。 按大小顺序列出所有排列情况&#xff0c;并一一标记&#xff0c;当 n 3 时, 所有排列如下&#xff1a; "123""132""213""231""312""321" 给定…...

【Cesium开发实战】视频融合功能的实现,可自定义位置和视频路径

Cesium有很多很强大的功能,可以在地球上实现很多炫酷的3D效果。今天给大家分享一个视频融合功能。 1.话不多说,先展示 视频融合 2.设计思路 点击绘制开始在地图上绘制视频融合的点位,形成视频播放的区域,双击弹框输入名称和要播放视频的路径,即可对应区域播放对应视频,…...

【秋招笔试题】小明的美食

解析&#xff1a;思维题。由于需要互不相同&#xff0c;每次操作取重复的值与最大值相加即可&#xff0c;这样即可保证相加后不会新增重复的值。因此统计重复值即可。 #include <iostream> #include <algorithm>using namespace std; const int maxn 1e5 5; int…...

基于OpenLCA、GREET、R语言的生命周期评价方法、模型构建及典型案例应用

生命周期分析 (Life Cycle Analysis, LCA) 是评价一个产品系统生命周期整个阶段——从原材料的提取和加工&#xff0c;到产品生产、包装、市场营销、使用、再使用和产品维护&#xff0c;直至再循环和最终废物处置——的环境影响的工具。这种方法被认为是一种“从摇篮到坟墓”的…...

Linux操作系统 -socket网络通信

同一台主机之间的进程 1.古老的通信方式 无名管道 有名管道 信号 2、IPC对象通信 system v 消息队列 共享内存 信号量集 由于不同主机间进程通信 3.socket网络通信 国际网络体系结构&#xff1a; 七层OSI模型(理论…...

【苍穹】完美解决由于nginx更换端口号导致无法使用Websocket

一、报错信息 进行到websocket开发的过程中&#xff0c;遇到了前端报错&#xff0c;无法连接的提示&#xff1a; 经过F12排查很明显是服务端和客户端并没有连接成功。这里就涉及到之前的坑&#xff0c;现在需要填上了。 二、报错原因和推导 应该还记得刚开苍穹的第一天配置前…...

Qt中在pro中实现一些宏定义

在pro文件中利用 DEFINES 定义一些宏定义供工程整体使用。&#xff08;和在cpp/h文件文件中定义使用有点类似&#xff09;可以利用pro的中的宏定义实现一些全局的判断 pro中实现 #自定义一个变量 DEFINES "PI\"3.1415926\"" #自定义宏 DEFINES "T…...

bash XXX.sh文件和直接运行XXX.sh的区别

区别&#xff1a; bash XXX.sh 明确说明使用bash作为脚本的解释器不需要文件有执行权限 XXX.sh 需要指定相关解释器。如果第一行是#!/bin/bash则使用bash&#xff0c;如果是#!/bin/sh&#xff0c;则使用sh作为解释器需要有执行权限:通过chmod x 文件名指定 注意: #!是特殊标…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...