vue搭建一个树形菜单项目

news2025/4/1 13:24:54

首先搭建项目需要先通过步骤搭建一个vue的项目,然后创建一个component文件,里面新建一个index.vue页面来。

这是引入的element-ui组件库里的组件,来实现我的路由,渲染的是我存储的动态路由,所以需要先安装并且引用。

npm install element-plus @element-plus/icons-vue

这是菜单管理的

<template>
  <div class="sidebar-container">
    <!-- 折叠控制 -->
    <div class="collapse-control" style="background-color:#293246" @click="toggleCollapse">
      <el-icon :size="20" :color="isCollapse ? '#fff' : '#ffd04b'">
        <component :is="isCollapse ? Expand : Fold" />
      </el-icon>
    </div>
    <!-- 导航菜单 -->
    <div>
      <el-menu router :default-active="$route.path" background-color="#293246" text-color="#fff" style="height: 100vh"
        active-text-color="#ffd04b" :collapse="isCollapse">
        <template v-for="menu in menuArray" :key="menu.path">
          <!-- 有子级的多层菜单项 -->
          <el-sub-menu v-if="menu.children?.length" index="/layout">
            <template #title>
              <span>{{ menu.meta.title }}</span>
            </template>
            <el-menu-item v-for="sub in menu.children" :key="'/layout' + sub.path" :index="'/layout' + sub.path">
              <span>{{ sub.title }}</span>
            </el-menu-item>
          </el-sub-menu>
          <!-- 没子级的单层菜单项 -->
          <el-menu-item v-else :index="menu.path == '/home' ? menu.path : menu.path">
            <span>{{ menu.meta.title }}</span>
          </el-menu-item>
        </template>
      </el-menu>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue'
import { Expand, Fold } from '@element-plus/icons-vue'
const isCollapse = ref(false)
const toggleCollapse = () => {
  isCollapse.value = !isCollapse.value
}
const menuArray = ref([]);
render();//初始化渲染
function render() {
  try {
    const menuList = JSON.parse(sessionStorage.getItem('menuPath') || '[]');
    const menuName = JSON.parse(sessionStorage.getItem('menuName') || '[]');
    console.log(menuList, menuName);
    if (!Array.isArray(menuList) || !Array.isArray(menuName)) {
      throw new Error('存储数据格式不正确');
    }
    const nameMap = new Map(menuName.map(item => [item.name, item]));
    menuArray.value = menuList
      .filter(item => item?.name && nameMap.has(item.name))
      .map(item => ({
        ...item,
        ...nameMap.get(item.name)
      }));
    console.log('安全筛选结果:', menuArray.value);
  } catch (error) {
    console.error('数据处理失败:', error);
    // 可以在这里设置默认值或进行错误上报
    return [];
  }
}
</script>
<style scoped>
.sidebar-container {
  transition: width 0.3s;
}

.collapse-control {
  padding: 15px;
  cursor: pointer;
  border-bottom: 1px solid #1f2d3d;
}

.el-menu--collapse {
  width: 64px;
}

.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
}
</style>

组件面包屑

<template>
  <!-- <div style="margin-bottom: 20px;width: 100%;">
    <el-button size="small" @click="addTab(editableTabsValue)">
      添加标签页
    </el-button>
  </div> -->
  <el-tabs v-model="editableTabsValue" @tab-click="tabBread" type="card" @tab-remove="removeTab">
    <el-tab-pane v-for="item in editableTabs" :key="item.name" :label="item.title"
      :name="item.name" :closable="item.name !== '/home'">
      <!-- 主页面 -->
      <el-main>
        <router-view />
      </el-main>
    </el-tab-pane>
  </el-tabs>
</template>

<script setup>
import { ref, reactive, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';

const route = useRoute();
const router = useRouter();

const editableTabsValue = ref(route.path);
const editableTabs = reactive([
  { title: '首页', name: '/home' }
]);

// 监听路由变化,同步标签页
watch(
  () => route.path,
  (newPath) => {
    editableTabsValue.value = newPath;
    if (!editableTabs.some(tab => tab.name === newPath)) {
      const title = getTitleFromPath(newPath);
      editableTabs.push({ title, name: newPath });
    }
  },
  { immediate: true }
);

function getTitleFromPath(path) {
  const titleMap = {
    '/home': '首页',
    '/layout/user/list': '用户列表',
    '/layout/user/role': '角色列表',
    // 扩展其他路由...
  };
  return titleMap[path] || '新标签';
}
// 点击面包屑标签跳转路由
const tabBread = () => {
  console.log(editableTabsValue.value);
  router.push(editableTabsValue.value);
}
const removeTab = (targetName) => {
  const tabs = editableTabs;
  let activeName = editableTabsValue.value;
  if (activeName === targetName) {
    const currentIndex = tabs.findIndex(tab => tab.name === targetName);
    const nextTab = tabs[currentIndex + 1] || tabs[currentIndex - 1];
    activeName = nextTab?.name || '/home';
    router.push(activeName);
  }
  editableTabsValue.value = activeName;
  editableTabs.splice(0, editableTabs.length, ...tabs.filter(tab => tab.name !== targetName));
};
</script>

<style scoped>
/* 可以添加自定义样式 */
.el-tabs {
  margin: 20px;
}
</style>

这部分代码是用来布局菜单框架结构的,然后我们在路由部分引入这个文件的路由即可。

<!-- src/layouts/MainLayout.vue -->
<template>
    <div class="app">
        <el-container style="height: 100vh;">
            <!-- 左侧导航栏 -->
            <el-aside width="200px">
                <aside-nav />
            </el-aside>
            <div class="menu">
                <!-- 顶部菜单 -->
                <MyHeader />
            </div>
        </el-container>
    </div>
</template>

<script>
import MyHeader from '@/Layout/topHeader.vue'
import AsideNav from '@/components/MenuItem.vue'

export default {
    components: {
        MyHeader,
        AsideNav
    }
}
</script>

<style>
html,
body {
    padding: 0;
    margin: 0;
}

.menu {
    width: 100%;
}
</style>

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

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

相关文章

具身智能 - Diffusion Policy:技术解析与应用实践

具身智能之 Diffusion Policy:技术解析与应用实践 一、Diffusion Policy 的核心概念 Diffusion Policy 是一种基于扩散模型(Diffusion Models)的决策生成框架,专为具身智能(Embodied Intelligence)设计。其核心思想是通过逐步去噪的过程,在复杂环境中生成鲁棒的动作序列…

[C++] 智能指针 进阶

标题&#xff1a;[C] 智能指针 进阶 水墨不写bug 在很久之前我们探讨了智能指针的浅显认识&#xff0c;接下来会更加深入&#xff0c;从源码角度认识智能指针&#xff0c;从而了解智能指针的设计原理&#xff0c;并应用到以后的工作项目中。 本文将会按照C智能指针的发展历史&…

kubernetes》》k8s》》 kubeadm、kubectl、kubelet

kubeadm 、kubectl 、kubelet kubeadm、kubectl和kubelet是Kubernetes中不可或缺的三个组件。kubeadm负责集群的快速构建和初始化&#xff0c;为后续的容器部署和管理提供基础&#xff1b;kubectl作为命令行工具&#xff0c;提供了与Kubernetes集群交互的便捷方式&#xff1b;而…

C++中的new、malloc、realloc、calloc——特点?函数原型?释放方式?区别?校招面试常问内容?

作者&#xff1a;求一个demo 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 内容通俗易懂&#xff0c;没有废话&#xff0c;文章最后是面试常问内容&#xff08;建议通过标题目录学习&#xff09; 废话不多…

27_promise

插入一下前端助手测试&#xff0c;顺手可以用来做安全 promise promise 是一个es6新增的语法 汉语&#xff1a;承诺的意思 作用:是专门用来解决回调地狱!!!! 什么是回调函数&#xff1f; <script>// 回调函数 callback回调// 就是把函数A当作参数传递到函数B中// 在函…

leetcode刷题日记——跳跃游戏 II

[ 题目描述 ]&#xff1a; [ 思路 ]&#xff1a; 题目要求在一个一定能达到数组末尾的跳跃数组中(见55题 跳跃游戏)&#xff0c;找出能够跳到末尾的最小次数要求次数最少&#xff0c;那肯定是选取能选步数中最大的数。也就是在当前能够达到的距离中&#xff0c;选择能够达到的…

无人机进行航空数据收集对于分析道路状况非常有用-使用无人机勘测高速公路而不阻碍交通-

无人机进行航空数据收集对于分析道路状况非常有用-使用无人机勘测高速公路而不阻碍交通- 瑞士拥有1,400 多公里长的高速公路网络。这些公路将人和货物从山谷高原运送到阿尔卑斯山的最高山口。维护这些高速公路使国家得以顺利运转。高速公路维护的重要性显而易见&#xff0c;但在…

注意力蒸馏技术

文章目录 摘要abstract论文摘要简介方法预备知识注意力蒸馏损失注意力引导采样 实验结论总结参考文献 摘要 本周阅读了一篇25年二月份发表于CVPR 的论文《Attention Distillation: A Unified Approach to Visual Characteristics Transfer》,论文开发了Attention Distillation…

PERL开发环境搭建>>Windows,Linux,Mac OS

特点 简单 快速 perl解释器直接对源代码程序解释执行,是一个解释性的语言, 不需要编译器和链接器来运行代码>>速度快 灵活 借鉴了C/C, Basic, Pascal, awk, sed等多种语言, 定位于实用性语言,既具备了脚本语言的所有功能,也添加了高级语言功能 开源.免费 没有&qu…

鸿蒙项目源码-记账本app个人财物管理-原创!原创!原创!

鸿蒙记账项目源码个人财务管理含文档包运行成功ArkTS语言。 我一个月写的原创作品&#xff0c;请尊重原创。 原创作品&#xff0c;盗版必究&#xff01;&#xff01;&#xff01; api12 SDK5.0.0仅适用于最新的2024版本DevEco studio 共9个页面&#xff1a;广告倒计时页、登录、…

Ovito的python脚本

在 OVITO 里,Python 对象是构建脚本化操作的基础。下面为你详细介绍 OVITO 中 Python 对象的基本概念: 1. 数据管道(Pipeline) 数据管道是 OVITO 里最核心的对象之一。它就像一个流水线,把数据输入进来,经过一系列处理步骤,最后输出处理好的数据。 创建管道:借助 imp…

【免费】2007-2019年各省地方财政文化体育与传媒支出数据

2007-2019年各省地方财政文化体育与传媒支出数据 1、时间&#xff1a;2007-2019年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;行政区划代码、地区、年份、地方财政文化体育与传媒支出 4、范围&#xff1a;31省 5、指标说明&#xff1a;地方财政在文化、…

NOIP2007提高组.矩阵取数游戏

题目 492. 矩阵取数游戏 思路 不难发现, 每一行之间是独立的, 因此可以求出每一行的最大值, 然后行与行之间最大值相加, 就是总的最大值 对于行内来说, 每次可以选取左边或者右边, 可以使用区间 d p dp dp求解, 时间复杂度 O ( n 3 ) O(n ^ 3) O(n3), 因为列的最大值是 80 …

项目实战--权限列表

后端数据&#xff1a; 用表格实现权限列表 const dataSource [{key: 1,name: 胡彦斌,age: 32,address: 西湖区湖底公园1号,},{key: 2,name: 胡彦祖,age: 42,address: 西湖区湖底公园1号,}, ];const columns [{title: 姓名,dataIndex: name,key: name,},{title: 年龄,dataInd…

若依赖前端处理后端返回的错误状态码

【背景】 后端新增加了一个过滤器&#xff0c;用来处理前端请求中的session 若依赖存放过滤器的目录&#xff1a;RuoYi-Vue\ruoyi-framework\src\main\java\com\ruoyi\framework\security\filter\ 【问题】 后端返回了一个状态码为403的错误&#xff0c;现在前端需要处理这…

【计网】数据包

期末复习自用的&#xff0c;处理得比较草率&#xff0c;复习的同学或者想看基础的同学可以看看&#xff0c;大佬的话可以不用浪费时间在我的水文上了 1.数据包的定义&#xff1a; 数据包是网络通信中的基本单元&#xff0c;它包含了通过网络传输的所有必要信息。数据包的结构…

web权限划分提权和移权

前言&#xff1a;权限的基本认知 渗透权限划分&#xff1a;假如我们通过弱口令进入到web的后台 这样我们就拿到了web的管理员权限 管理员权限是web中最高的权限&#xff08;一般我们进入web的时候数据库会进行用户权限的划分&#xff1a;假设 0-10为最高的权限 11-10000为普通…

LocalDateTime序列化总结

版权说明&#xff1a; 本文由CSDN博主keep丶原创&#xff0c;转载请保留此块内容在文首。 原文地址&#xff1a; https://blog.csdn.net/qq_38688267/article/details/146703276 文章目录 1.背景2.序列化介绍常见场景关键问题 3.总体方案4.各场景实现方式WEB接口EasyExcelMybat…

[ 春秋云境 ] Initial 仿真场景

文章目录 靶标介绍&#xff1a;外网内网信呼oa永恒之蓝hash传递 靶标介绍&#xff1a; Initial是一套难度为简单的靶场环境&#xff0c;完成该挑战可以帮助玩家初步认识内网渗透的简单流程。该靶场只有一个flag&#xff0c;各部分位于不同的机器上。 外网 打开给的网址, 有一…

unity 截图并且展现在UI中

using UnityEngine; using UnityEngine.UI; using System.IO; using System.Collections.Generic; using System; using System.Collections;public class ScreenshotManager : MonoBehaviour {[Header("UI 设置")]public RawImage latestScreenshotDisplay; // 显示…