ant-design-vue三级菜单

2023-12-19

<template>
  <div class="MySider">
    <div class="logo" @click="handleCollapsed" :class="{ collapsed: collapsed }">
      <img :src="collapsed ? logo_c : logo" />
    </div>
    <a-menu theme="light" v-model:openKeys="openKeys" v-model:selectedKeys="selectedKeys" mode="inline"
      :inlineCollapsed="collapsed">
      <template v-for="item of showList" :key="item.path">
        <a-menu-item :key="item.path" v-if="item.meta.is_leaf" @click="routerChange(item.path)">
          <i class="icon" :class="item.meta.icon" />
          <span :class="{ 'collapsed-title': collapsed }">{{
            item.meta.title_zh
          }}</span>
        </a-menu-item>
        <a-sub-menu :key="'sub-menu' + item.path" v-else>
          <template #title>
            <i class="icon" :class="item.meta.icon" />
            <span v-show="!collapsed">{{ item.meta.title_zh }}</span>
          </template>
          <template v-for="i of item.children">
            <a-sub-menu :key="'sub-menu' + i.path" v-if="i.children && i.children.length > 0">
              <template #title>
                <span>{{ i.meta.title_zh }}</span>
              </template>

              <!-- 循环显示三级菜单项 -->
              <template v-for="j of i.children">
                <a-menu-item :key="'sub-menu' + i.path + '/' + j.path" @click="routerChange(i.path + '/' + j.path)"
                  v-if="showMenuItem(j)">
                  <span>{{ j.meta.title_zh }}</span>
                </a-menu-item>
              </template>
            </a-sub-menu>

            <!-- 如果没有三级菜单,则显示二级菜单项 -->
            <a-menu-item :key="'sub-menu' + item.path + '/' + i.path" @click="routerChange(item.path + '/' + i.path)"
              v-else-if="showMenuItem(i)">
              <span>{{ i.meta.title_zh }}</span>
            </a-menu-item>
          </template>
        </a-sub-menu>
      </template>
    </a-menu>
  </div>
</template>
<!-- item.children.length === 1 || -->
<script setup>
import { storeToRefs } from "pinia";
import { ref, watch, computed, getCurrentInstance } from "vue";
import { useRoute, useRouter } from "vue-router";

import logo from "@/assets/images/logo.png";
import logo_c from "@/assets/images/logo-c.png";

import Core from "@/core";
import routes from "@/router/routes";
import useStore from "@/core/store/index.js";

const route = useRoute();
const router = useRouter();
const { permission } = useStore();
const { permissionObj, showList } = storeToRefs(permission);
const { getRouterArray } = permission;
const emits = defineEmits(["collapsed"]);

const userType = Core.Data.getUserType();
// 获取展示用列表
getShowList();
function getShowList() {
  getRouterArray();
}

const openKeys = ref([]);
const selectedKeys = ref([route.path]);
// 获取当前展开
for (const item of routes) {
  if (item.hidden || item.children.length === 1) {
    continue;
  }
  for (const i of item.children) {
    if (item.path + "/" + i.path === route.path) {
      openKeys.value = [item.path];
      break;
    }
  }
}
// 获取当前高亮
watch(
  () => route,
  (n) => {
    console.log("watch route n:", n);
    if (n.matched && n.matched.length >= 2) {
      let firstItem = n.matched[0];
      let lastItem = n.matched[n.matched.length - 1];
      if (firstItem?.meta?.is_leaf) {
        selectedKeys.value = [firstItem.path];
      } else {
        selectedKeys.value = [lastItem.path];
      }
    } else {
      selectedKeys.value = [n.path];
    }
    // console.log('selectedKeys.value:', selectedKeys.value)
  },
  { deep: true, immediate: true }
);

// 路由跳转
function routerChange(path) {
  console.log("routerChange path:", path);
  router.push(path);
}

// 二级菜单的展示控制
function showMenuItem(i) {
  const auth = i.meta ? i.meta.auth || [] : [];
  const roles = i.meta ? i.meta.roles : "";
  return (
    Core.Util.auth(...auth) && !i.hidden && (!roles || roles.includes(userType))
  );
}

// 展开收缩
const collapsed = ref(false);
function handleCollapsed() {
  collapsed.value = !collapsed.value;
  emits("collapsed", collapsed.value);
  if (collapsed.value) {
    window.document.getElementById("showLayoutSider").style.left = "80px";
  } else {
    window.document.getElementById("showLayoutSider").style.left = "180px";
  }
}
</script>

<style lang='scss' scoped>
.MySider {
  height: 100vh;

  .logo {
    width: 100%;
    height: 50px;
    display: flex;
    align-items: center;
    overflow: hidden;

    // border-bottom: 1px solid #e6eaee;
    img {
      max-width: calc(100% - 40px);
      margin-left: 20px;
    }

    &.collapsed {
      justify-content: center;

      img {
        max-width: calc(80%);
        max-height: 70%;
        margin-left: 0;
      }
    }
  }

  i.icon {
    margin-right: 14px;
    font-size: 14px;
    transition: color 0.3s;
  }

  .collapsed-title {
    padding-left: 50px;
  }

  .ant-menu.ant-menu-inline {
    height: calc(100% - 50px);
    overflow-y: auto;
    overflow-x: hidden;
    border-right: 0;

    .ant-menu-item {
      height: 40px;
      line-height: 40px;
      margin: 0;
    }

    .ant-menu-submenu-title {
      height: 40px;
      line-height: 40px;
      margin: 0;
    }

    .ant-menu-submenu {
      .ant-menu-item {
        margin-bottom: 0;
      }
    }

    @include scrollbar(2px);
  }

  .ant-menu-inline .ant-menu-item,
  .ant-menu-inline .ant-menu-submenu-title {
    width: 100%;
    font-size: 13px !important;
    color: #334d6e;

    .icon {
      color: #c2cfe0;
    }
  }

  .ant-menu-inline-collapsed {
    border: 0;
  }

  li.ant-menu-item {
    background-color: transparent !important;
  }

  ul.ant-menu-sub {
    background-color: transparent;
  }

  .ant-menu-item-selected::after {
    display: none;
  }

  .ant-menu-item-selected .ant-menu-title-content,
  .ant-menu-item:hover .ant-menu-title-content {
    color: $primary;

    .icon {
      color: $primary;
    }
  }

  .ant-menu-submenu.ant-menu-submenu-selected .ant-menu-submenu-title,
  .ant-menu-submenu .ant-menu-submenu-title:hover {
    color: $primary;

    .icon {
      color: $primary;
    }

    .ant-menu-submenu-arrow {
      color: $primary;
    }
  }

  .ant-menu-submenu .ant-menu-item .ant-menu-title-content {
    padding-left: 4px;
  }
}

.ant-menu-inline-collapsed-tooltip {
  font-size: 13px;

  i.icon {
    display: none;
  }
}

.ant-menu-vertical.ant-menu-sub>.ant-menu-item {
  width: 100%;
  font-size: 13px !important;
  margin: 4px 0 !important;
  height: 32px;
  line-height: 32px;
}
</style>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ant-design-vue三级菜单 的相关文章

随机推荐

  • 如何在项目管理中跟踪资源可用性?

    项目是有计划 有安排的 在不超支预算的情况下按期执行项目 项目经理必须了解资源的可用性 这是资源管理流程的一部分 什么是资源可用性 资源可用性是指了解执行项目所需的资源 何时需要以及在何种情况下需要 能够协调完成项目所需的资源 是项目成功的
  • 2023 年排名前八的 Kali Linux 工具

    一 排名前八的 Kali Linux 渗透测试工具 信息收集 密码破解 社交工程 网络犯罪对我们的 IT 世界构成严重威胁 并且可以采用许多不同的策略来打击它 道德黑客 也称为 白黑客 使用各种网络安全工具来测试网络和数据系统是否存在黑客可
  • 为什么要学习Python?

    前言 Python 是当今非常流行的编程语言 在互联网上经常可以看到他的身影 它应用非常广泛 例如编程 Web 开发 机器学习和 数据科学Q 等 TIOBE 官网近日公布了 2023 年 8 月的编程语言排行榜 Python 依然排行第一
  • 免费、好用!IDEA插件用这款!

    IDEA插件市场中的API调试插件不是收费 Fast Request 就是不好用 apidoc apidocx等等 今天给大家介绍一款国产的API调试插件 Apipost Helper 完全免费且好看好用 这款插件由Apipost团队开发的
  • 要想用好linux,先把shell 搞明白

    一 变量 1 环境变量 echo PATH 2 自定义变量 hello hello world echo hello 3 存储 Linux 命令执行结果作为变量 2 种方式 推荐使用第二中 第一种是 键上面的斜点比较难识别 files ls
  • API调试神器!Apipost

    前言 Apipost是一款支持 RESTful API SOAP API GraphQL API等多种API类型 支持 HTTPS WebSocket gRPC多种通信协议的API调试工具 除此之外 Apipost 还提供了自动化测试 团队
  • 元宇宙3d展厅全景导览系统为现代展会的举办带来了全新的可能性和机遇。

    3D元宇宙展会搭建平台的亮点 随着科技的不断进步 3D元宇宙展会搭建平台已经成为了现代展会的新趋势 这种全新的展会形式不仅给人们带来了前所未有的视觉体验 还具备许多亮点和优势 让展会的举办更加高效 便捷和创新 一 突破时空限制 3D元宇宙展
  • 软件测试/测试开发/人工智能丨如何通过分组 AUC 从不同的维度验证模型的能力

    通过分组 AUC Area Under the Curve 从不同维度验证模型的能力是一种有效的方法 特别适用于面对多个子群体或子问题的场景 以下是一些步骤 以及在不同维度验证模型性能时可能的一些策略 步骤 定义分组维度 确定模型性能需要在
  • 简单搭建一个Python自动化测试框架

    1 安装 Python 首先需要安装Python 可以从官网下载对应的版本 安装完成后 可以在终端中输入python来检查是否安装成功 2 安装pip pip是Python的包管理工具 用于安装和管理Python模块 可以在终端中输入以下命
  • zkSend — — 在Sui上发红包像发电子邮件一样简单

    12月14日 知名区块链媒体平台The Block发表了这篇关于对Mysten Labs联合创始人Adeniyi Abiodun的采访 文中 我们 指代该媒体 数据均为截止撰写文章时数据 以下是正文 两年前 当五名前Facebook工程师创
  • 玩转Docker(七):Docker Compose

    文章目录 一 什么是Docker Compose 二 一个完整的例子 一 什么是Docker Compose Docker Compose是一个用于定义和运行多个Docker容器应用的工具 它使用YAML文件来配置应用的服务 网络 卷等 通
  • NFTScan | 12.11~12.17 NFT 市场热点汇总

    欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总 周期 2023 12 11 2023 12 17 NFT Hot News 01 Pudgy Penguins 衍生 NFT Lil Pudgys 过去一天
  • nodejs使用nodejieba

    Nodejieba是一个基于Node js平台的中文分词模块 用于将中文文本切分成有意义的词汇 它是结巴中文分词的Node js版本 结巴分词是一种开源的中文分词工具 广泛应用于中文自然语言处理领域 优点 高性能 Nodejieba的底层实
  • 判断API接口优劣的标准

    随着互联网的发展 API接口已经成为了应用程序之间进行数据交互的重要方式 然而 在众多的API接口中 如何判断其优劣呢 本文将介绍一些判断API接口优劣的标准 一 稳定性和可用性 一个优秀的API接口必须具备稳定性和可用性 稳定性是指接口在
  • 蚂蚁集团5大开源项目获开放原子 “2023快速成长开源项目”

    12月16日 在开放原子开源基金会主办的 2023开放原子开发者大会 上 蚂蚁集团主导开源的图数据库TuGraph 时序数据库CeresDB 隐私计算框架隐语SecretFlow 前端框架OpenSumi 数据域大模型开源框架DB GPT入
  • 【ranger】CDP环境 更新 ranger 权限策略会发生低概率丢失权限策略的解决方法

    一 问题描述 我们的 kafka 服务在更新 添加 ranger 权限时 会有极低的概率导致 MM2 同步服务报错 报错内容 Not Authorized 但是查看 ranger 权限是赋予的 并且很早配置的权限策略也会报错 相关组件版本
  • 软件测试/测试开发|最容易上手的Ubuntu虚拟机安装教程

    简介 我们在日常的学习和工作中 经常需要我们在Linux系统上部署环境或者执行测试 但是有时候服务器资源并没有这么好申请 特别是当我们在学习时 购买服务器会增加我们的成本 在这个时候 我们就可以使用虚拟机了 我们使用虚拟机来安装Linux系
  • 用友出席操作系统大会,携手麒麟软件深度服务企业数智化

    12月15日 操作系统大会 openEulerSummit2023在北京召开 用友受邀参加麒麟软件分论坛 与行业大咖一道 共话产业链生态引领基础软件加速技术创新 在企业数智化转型大潮中 用友聚合各行各业生态伙伴 共同营建全球领先的数智商业创
  • 云服务器1核1G能干什么?

    随着云计算技术的不断发展 云服务器已经成为企业和个人用户的重要选择 其中 1核1G的云服务器是市场上比较常见的一种配置 那么 1核1G的云服务器有哪些用途呢 搭建小型网站或个人博客 对于一些小型网站或个人博客来说 并不需要太多的计算资源和存
  • ant-design-vue三级菜单