vue3 + ant-design-vue@3.x 根据路由生成 多级递归嵌套菜单

首先全局注册图标

import { createApp } from "vue";
import { createFromIconfontCN } from "@ant-design/icons-vue";

// 注册远程 icon
const Icon = createFromIconfontCN({
	// 这个是我自己的图标库,你自己创建要去 iconfont.cn 上创建,看官网教程 https://next.antdv.com/components/icon-cn#%E8%87%AA%E5%AE%9A%E4%B9%89-font-%E5%9B%BE%E6%A0%87
    scriptUrl: "//at.alicdn.com/t/font_3013134_pc3mmckqy1.js", // 在 iconfont.cn 上生成
});
const app = createApp(App);
app.use(router)
    .use(antd)
    .component("Icon", Icon)
    .mount("#app");

配置路由,meta 中的 open 代表此路由是否默认展开

import { createMemoryHistory, createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

export const routes: RouteRecordRaw[] = [
    {
        path: "/",
        name: "index",
        component: () => import("@/view/index.vue"),

        children: [
            {
                path: "/dashboard",
                name: "dashboard",
                meta: {
                    title: "导航栏",
                    icon: "icon-dashboard",
                },
                component: () => import("@/view/dashboard/index.vue"),
            },
            {
                path: "/user",
                name: "user",
                meta: {
                    title: "个人信息",
                    icon: "icon-user",
                },
                component: () => import("@/view/user/index.vue"),
            },
            {
                path: "/tables",
                name: "tables",
                meta: {
                    title: "信息管理",
                    icon: "icon-table",
                    open: true,
                },
                component: () => import("@/view/tables/index.vue"),
                children: [
                    {
                        path: "user",
                        name: "tables-user",
                        component: () => import("@/view/tables/user/index.vue"),
                        meta: {
                            title: "用户管理",
                            icon: "icon-team",
                        },
                    },
                    {
                        path: "blog",
                        name: "tables-blog",
                        component: () => import("@/view/tables/blog/index.vue"),
                        meta: {
                            title: "文章管理",
                            icon: "icon-file-text",
                        },
                    },
                ],
            },
            {
                path: "/setting",
                name: "setting",
                meta: {
                    title: "系统设置",
                    icon: "icon-setting",
                },
                component: () => import("@/view/setting/index.vue"),
            },

            {
                path: "/:pathMatch(.*)*",
                name: "404",

                component: () => import("@/view/components/NotFound.vue"),
                meta: {
                    title: "404",
                    icon: "icon-infos",
                },
            },
        ],
    },
    {
        path: "/login",
        name: "login",
        component: () => import("@/view/login/index.vue"),
    },
];

// 菜单主路由
export const menuRoutes = routes.find((r) => r.name === "index");
// 当前路由
export const currentRoute = menuRoutes?.children?.find((r) => r.path === window.location.pathname);

export const router = createRouter({
    history: createWebHistory(),
    routes: routes,
});

Menus.vue

<template>
    <!-- 多级嵌套路由 -->
    <a-menu
        v-model:selectedKeys="layoutStatus.selectedKeys"
        :open-keys="layoutStatus.openKeys"
    >
        <!-- 遍历菜单路由 -->
        <template v-for="route of menuRoutes.children">
            <RouteMenus :route="route" />
        </template>
    </a-menu>
</template>

<script setup lang="ts">
import { ref, reactive, toRefs } from "vue";
import { MenuProps } from "ant-design-vue";
import { menuRoutes } from "../../../route";
import { layoutStatus } from "../../../store/status";

import RouteMenus from "./RouteMenus.vue";

interface MenusProps extends MenuProps {}

withDefaults(defineProps<MenusProps>(), {});
</script>

<style scope lang="less"></style>

RouteMenus.vue 嵌套路由

<template>
    <!-- 如果存在子路由 -->
    <template v-if="route.children">
        <a-sub-menu :key="route.name" :title="route.meta?.title || '未命名'">
            <template #icon>
                <Icon v-if="route.meta?.icon" :type="route.meta.icon" />
            </template>
            <template v-for="children of route.children">
                <!-- 递归 -->
                <RouteMenus :route="children" />
            </template>
        </a-sub-menu>
    </template>
    <template v-else>
        <a-menu-item :key="route.name" @click="router.push(route.path)">
            <Icon v-if="route.meta?.icon" :type="route.meta.icon" />
            <span class="nav-text"> {{ route.meta?.title || "未命名" }} </span>
        </a-menu-item>
    </template>
</template>

<script setup lang="ts">
import { ref, reactive, toRefs } from "vue";
import { RouteRecordRaw } from "vue-router";
import { router } from "../../../route";

interface RouteMenusProps {
    route: RouteRecordRaw;
}
const props = withDefaults(defineProps<RouteMenusProps>(), {});
const {} = toRefs(props);
</script>

<style scope lang="less"></style>

效果
在这里插入图片描述
现在可以直接在路由动态修改菜单,或者使用远程数据

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值