ant-design-vue三级菜单

<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>

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用 Cascader 组件来实现 ant-design-vue三级联动。Cascader 组件是一个级联选择器,可以方便地实现多级联动选择。您可以在 Cascader 组件中设置 options 属性来定义选项列表,然后在 onChange 事件中获取选中的值。以下是一个示例代码: ``` <template> <a-cascader :options="options" v-model="selectedValues" @change="handleChange"></a-cascader> </template> <script> export default { data() { return { options: [ { value: 'beijing', label: '北京', children: [ { value: 'dongcheng', label: '东城', children: [ { value: 'tiananmen', label: '天安门' }, { value: 'wangfujing', label: '王府井' } ] }, { value: 'xicheng', label: '西城', children: [ { value: 'xidan', label: '西单' }, { value: 'fuchengmen', label: '阜成门' } ] } ] }, { value: 'shanghai', label: '上海', children: [ { value: 'pudong', label: '浦东', children: [ { value: 'lujiazui', label: '陆家嘴' }, { value: 'zhangjiang', label: '张江' } ] }, { value: 'puxi', label: '浦西', children: [ { value: 'nanjinglu', label: '南京路' }, { value: 'thebund', label: '外滩' } ] } ] } ], selectedValues: [] } }, methods: { handleChange(value) { console.log(value) } } } </script> ``` 在这个示例中,我们定义了一个 options 数组,其中包含了北京和上海两个城市,每个城市下面又包含了两个区域,每个区域下面又包含了两个街道。当用户选择某个选项时,会触发 onChange 事件,我们可以在事件处理函数中获取到用户选择的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值