vue3 antd 多级菜单 v-for

  • 前言引入
  • 场景复现
  • 解决方案🔥
  • 整体搭建 layout布局
  • 左侧菜单栏 Menu🔥
  • summary
  • 下期预告
  • vue3后台管理系统 菜单栏两种方式处理有无children的问题🔥🔥
  • vue3搜索的筛选功能🔥

前言引入

一个完整的后台管理系统一定离不开各个分工的页面,其中作为门户的是登录页面,登录后的页面为主页面。顾名思义,主页面能够容纳所有的元素,实现各种跳转。主页面包括导航栏(左侧和顶部)主要内容区

👏👏👏本期文章将用v-for循环实现多级菜单栏
下期文章将分享菜单栏的优化版本,解决对children的判断。👏👏👏

场景复现

从零开始的后台管理系统,需要一个基础的Home页面,Home页面需要有完善的menu菜单。

下面是大致的实现效果:👇👇👇

ant design vue 动态改变button ant design pro vue 动态菜单_前端

解决方案🔥

先上源码 具体步骤后续详细说明👇👇👇
Home.vue(部分)

<script setup lang="ts">
import { defineComponent, ref, watch, reactive } from 'vue';
import type { MenuProps } from 'ant-design-vue';
import { useRouter } from 'vue-router'

    const router = useRouter();
    const list = router.getRoutes().filter(v => v.meta.isShow); // filter过滤出子路由中对页面渲染的结果
    console.log(list);

    const selectedKeys = ref<string[]>(['it.path']);
    const openKeys = ref<string[]>(['i.path']);
    const handleClick: MenuProps['onClick'] = e => {
    console.log('click', e);
};
const titleClick = (e: Event) => {
    console.log('titleClick', e);
};
    watch(
        () => openKeys,
        val => {
            console.log('openKeys', val);
        },)
</script>

<template>
    <a-layout class="container">
        <div class="slider">
            <a-layout-sider>
                <div class="text"><a>后台管理系统</a></div>
                <a-menu class="menu" style="width: 200px" mode="inline" theme="dark" v-model:openKeys="openKeys"
                    v-model:selectedKeys="selectedKeys" @click="handleClick">
                    <a-sub-menu v-for="i in list" :key="i.path" :index="i.path" @titleClick="titleClick">
                        <template #icon>
                            <component class="icons" :is="i.meta?.icon"></component>
                        </template>
                        <template #title class="title">
                            <router-link :to="'/home'">{{i.meta.title}}</router-link>
                        </template>
                        <a-menu-item v-for="it in i.children" :index="'/' + it.path" :key="it.path">
                            <template #icon>
                                <component class="icons" :is="it.meta?.icon"></component>
                            </template>
                            <router-link :to="i.path + '/' + it.path">
                                <span>{{ it.meta?.authName }}</span>
                            </router-link>
                        </a-menu-item>
                    </a-sub-menu>
                </a-menu>
            </a-layout-sider>
        </div>
        <a-layout>
            <a-layout-header height="80px" class="header" style="width:100%">
                <a-row>
                    <a-col :span="8"><a>管理服务1</a></a-col>
                    <a-col :span="8"><a>管理服务2</a></a-col>
                    <a-col :span="8"><a>管理服务3</a></a-col>
                </a-row>
            </a-layout-header>
            <a-layout-content style="width:100%">
                <router-view/>
            </a-layout-content>
        </a-layout>
    </a-layout>
</template>

router.ts(部分)

{
        path: '/home',
        component: () => import("../view/Home.vue"), // 按需引入
        // 子路由
        children:[
            { // 子路由1
                path: '', // 子路由不用斜杠
                name: 'home',
                meta:{
                    isShow:true, // 是否要在左侧区域渲染
                    title:"2022新生",
                    threeMenu: true,
                    icon:'MailOutlined',
                },
                // component: () => import("../view/Order.vue"), // 按需引入
                children:[
                    {
                        path: 'order',
                        name: 'order',
                        meta:{
                            authName:"新生文章区",
                            hidden: false, // 初始状态为隐藏
                            icon:'AppleOutlined',
                        },
                        component: () => import("../view/order.vue") // 按需引入
                    },
                    {
                        path: 'about_1',
                        name: 'about_1',
                        meta:{
                            authName:"新生瓷片区",
                            hidden: false,
                            icon:'InboxOutlined',
                        },
                        component: () => import("../view/About_1.vue") // 按需引入
                    },
                ]
            },
         }

整体搭建 layout布局

在ant design vue组件库中,layout布局可以直接复用。

ant design vue 动态改变button ant design pro vue 动态菜单_typescript_02

<a-layout>
    <a-layout-sider>Sider</a-layout-sider>
    <a-layout>
      <a-layout-header>Header</a-layout-header>
      <a-layout-content>Content</a-layout-content>
      <!--这里的footer暂时用不到-->
      <!--<a-layout-footer>Footer</a-layout-footer>-->
    </a-layout>
  </a-layout>

左侧菜单栏 Menu🔥

ant design vue提供了全面的Menu菜单组件 可以直接复用

ant design vue 动态改变button ant design pro vue 动态菜单_前端_03


详细解释➕组件库api说明

<a-menu class="menu" style="width: 200px" mode="inline" theme="dark" v-model:openKeys="openKeys" v-model:selectedKeys="selectedKeys" @click="handleClick">
<!-- 内嵌式菜单 主题色黑色 点击事件-->
     <!-- 一级菜单-->
     <a-sub-menu v-for="i in list" :key="i.path" :index="i.path" @titleClick="titleClick">
     <!--下拉菜单栏  循环list中的元素i key值为i的path 标题点击事件-->
         <template #icon>
         <!-- icon引入-->
             <component class="icons" :is="i.meta?.icon"></component> 
             <!--icon的引入方式 按需引入 循环i中meta下的icon-->
         </template>
         <template #title class="title">
             <router-link :to="'/home'">{{i.meta.title}}</router-link>
             <!-- 用router-link实现点击跳转home页面-->
         </template>
         <!--二级菜单-->
         <a-menu-item v-for="it in i.children" :index="'/' + it.path" :key="it.path">
             <template #icon>
                 <component class="icons" :is="it.meta?.icon"></component>
                 <!--icon的引入方式 按需引入 循环i中meta下的icon-->
              </template>
              <!-- router-link跳转响应一级菜单路径下的二级菜单路径-->
              <router-link :to="i.path + '/' + it.path">
                  <span>{{ it.meta?.authName }}</span>
                  <!-- 循环显示二级菜单内容中的meta下的authName-->
              </router-link>
         </a-menu-item>
     </a-sub-menu>
 </a-menu>

ant design vue 动态改变button ant design pro vue 动态菜单_vue.js_04

ant design vue 动态改变button ant design pro vue 动态菜单_anti-design-vue_05


ant design vue 动态改变button ant design pro vue 动态菜单_anti-design-vue_06


ant design vue 动态改变button ant design pro vue 动态菜单_前端_07


ant design vue 动态改变button ant design pro vue 动态菜单_typescript_08


ant design vue 动态改变button ant design pro vue 动态菜单_前端_09


ant design vue 动态改变button ant design pro vue 动态菜单_前端框架_10


不难发现,这样只是简单的实现了效果,但是很多细节仍需优化,比如有无子菜单的区分循环、菜单样式的渲染、路由的简化等。下期文章将对其做出优化,给出完善后的菜单渲染。

summary

组件库对于页面的构建十分重要,如果使用组件存在不足,可以移步官方文档。