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

vue搭建一个树形菜单项目

首先搭建项目需要先通过步骤搭建一个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.kler.cn/a/614149.html

相关文章:

  • std::countr_zero
  • 如何让AI套用现有ppt模板,并通过改文字批量生成新的ppt?【翻车版】
  • 【动态规划篇】- 路径问题
  • uniapp用法--uni.navigateTo 使用与参数携带的方式示例(包含复杂类型参数)
  • 【AI知识】深度学习中模型参数初始化方法介绍
  • 【Hugging Face 开源库】Diffusers 库 —— 扩散模型
  • 【STM32】知识点介绍二:GPIO引脚介绍
  • Markdown 和 Microsoft Word对比
  • C++细节知识for面试
  • 【老电脑翻新】华硕A456U(换电池+换固态+光驱换机械+重装系统+重装系统后开始菜单失灵问题解决)
  • 【附代码】【MILP建模】3D装箱问题(3D-Bin Packing Problem)
  • LVS的 NAT 模式实验
  • QT:信号映射器
  • 力扣上C语言编程题
  • PHP开发者2025生存指南
  • 【数据分享】2000—2024年我国乡镇的逐年归一化植被指数(NDVI)数据(年最大值/Shp/Excel格式)
  • 浙大:DeepSeek技术溯源及前沿探索
  • ORBITVU 欧保图,开启自动化摄影新时代
  • K-均值聚类算法:数据海洋中的分类灯塔
  • 标星 62.9 万,8 个 yyds 的 GitHub 开源项目 !