vue3+antd4实现左侧多级菜单栏 递归渲染

上一篇讲到用判断去实现菜单渲染,但这样比较生硬,且不利于维护。因此本篇使用了递归思想去解决。

留意第三个一级菜单的路由配置的showMenu为false,因为只展示的是一级菜单。

第一步:首先新建一个RecursiveMenu.vue的文件,用于递归菜单数据。

<template>
    <div>
        <template v-for="item in menus.menus"> // 这里使用的是menus.menus
            <!-- 判断是否有子菜单且是否显示 -->
            <a-sub-menu v-if="item.children && item.children.length > 0 && item.meta.showMenu" :key="item.name">
              <template #title>
                <span>{{ item.meta.title }}</span>
              </template>
              <!-- 递归调用 RecursiveMenu 组件来渲染子菜单 -->
              <recursive-menu :menus="item.children" @navigate="handleNavigation" />
            </a-sub-menu>
            <!-- 没有子菜单,直接显示菜单项 -->
            <a-menu-item v-else-if="!item.meta.showMenu" :key="item.name" @click="handleNavigation(item)" :title="item.meta.title">
              {{ item.meta.title }}
            </a-menu-item>
    </template>
    </div>
</template>

<script setup lang='ts'>
let menus = defineProps(['menus'])
    
const emit = defineEmits(["navigate"])
    const handleNavigation = (item:any) => {
        
      emit('navigate', item);
    }
</script>

<style lang='less' scoped>
    
</style>

其次在layout文件中使用:

<template>
  <a-layout class="components-layout-demo-custom-trigger">
    <a-layout-sider :trigger="null" :collapsible="true" class="layoutSide">
      <a-menu mode="inline"
      >

        <recursive-menu :menus="menus" @navigate="toPage" /> <=======
递归文件
===================>


      </a-menu>
      </a-layout-sider>
    <a-layout class="layoutContent">
      <a-layout-header>
      </a-layout-header>
      <a-layout-content
        :style="{
          margin: '10px',
          padding: '20px',
          background: '#fff',
          minHeight: 'calc(100% - 160px)',
          overFlow: 'hidden',
          overflowY: 'auto',
          borderRadius: '10px'
        }"
      >
      <!-- 内容展示区 -->
        <router-view></router-view>
      </a-layout-content>
    </a-layout>
  </a-layout>
</template>

<script setup lang="ts">
import { reactive } from 'vue';
  import { useRoute, useRouter } from 'vue-router';
  import route from '@/router/index.ts'; // 引入第三步的路由
  import recursiveMenu from './RecursiveMenu.vue' // 引入第一步的递归文件
  import menusList from '@/router/index.ts'


let menus = reactive([])
Object.assign(menus, menusList.options.routes)
console.log('menus', menus, menusList);

let toPage = (val:object) => {
  router.push({
    path: val.path
  })
}
</script>

第三步:路由配置

import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/components/layout/index.vue'
import webApplication from '@/views/assetDataMaintenance/itEquipment/safetyEquipment/webApplication/index.vue'


const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: '1',
      component: Layout,
      redirect: '/itEquipment/safetyEquipment/webApplication',
      meta: {
        title: '一级菜单',
        showMenu: true  //  菜单项被标记为是否可显示
      },
      children: [
        {
          path: '/itEquipment',
          name: 'itEquipment',
          // component: webApplication,
          meta: {
            title: '二级菜单',
            showMenu: true
          },
          children: [{
            path: '/itEquipment/safetyEquipment',
            name: 'safetyEquipment',
            // component: webApplication,
            meta: {
              title: '三级菜单',
              showMenu: true
            },
            children: [{
              path: '/itEquipment/safetyEquipment/webApplication',
              name: 'webApplication',
              component: webApplication,
              meta: {
                title: '四级菜单1',
                showMenu: false
              }
            },
            {
              path: '/itEquipment/safetyEquipment/logCollectionAnalysisSystem',
              name: 'logCollectionAnalysisSystem',
              component: () => import('@/views/assetDataMaintenance/itEquipment/safetyEquipment/logCollectionAnalysisSystem/index.vue'),
              meta: {
                title: '四级菜单2',
                showMenu: false
              }
            }]
          }]
        }
      ]
    },
    {
      path: '/assetDataManagement',
      name: 'assetDataManagement',
      component: Layout,
      meta: {
        title: '一级菜单',
        showMenu: true
      },
      children: [
        {
          path: '/assetDataManagement/changeManagement',
          name: 'changeManagement',
          component: () => import('@/views/assetDataManagement/changeManagement/index.vue'),
          meta: {
            title: '二级菜单',
            showMenu: false
          }
        },
      ]
    },
    {
      path: '/ldap',
      name: 'ldap',
      component: Layout,
      meta: {
        title: '一级菜单',
        showMenu: false   // 这里设置为false,是因为这个只显示一级菜单
      },
      children: [{
        path: '/ldap',
        name: 'ldap',
        component: () => import('@/views/ldap/index.vue'),
        meta: {
          title: '二级菜单',
          showMenu: false
        },
      }

      ]
    },
    {
      path: '/system',
      name: 'system',
      component: Layout,
      meta: {
        title: '一级菜单',
        showMenu: true
      },
      children: [{
        path: '/paramsModel',
        name: 'paramsModel',
        component: () => import('@/views/system/paramsModel/index.vue'),
        meta: {
          title: '二级菜单',
          showMenu: false
        },
      }

      ]
    },
    {
      path: '/login',
      name: 'login',
      component: () => import('@/views/login/index.vue'),
      meta: {
        title: '登录',
        showMenu: true
      }
    },
    {
      path: '/404',
      name: 'errorPage',
      component: () => import('@/views/errorPage/index.vue'),
      meta: {
        title: '404',
        showMenu: true
      }
    }
  ]
})

export default router

对RecursiveMenu.vue的文件的理解:

1. 加载组件:当你在父组件中使用 <recursive-menu :menus="menus" /> 时,Vue.js 会创建 RecursiveMenu 组件的实例。

2. 传递 Props:menus 数据作为 prop 传递给 RecursiveMenu 组件。这个数据包含了整个菜单结构,每个菜单项可能有 children 属性,表示其子菜单。

3. 渲染菜单:组件的模板部分使用 v-for 指令遍历 menus 数组。对于每个 item(菜单项),组件会检查是否满足以下条件:
- item.children && item.children.length > 0:菜单项有子菜单。
- item.meta.showMenu:菜单项被标记为可显示。

4. 条件渲染:
- 如果上述条件为真,说明当前菜单项有子菜单且应该显示,组件会渲染一个 <a-sub-menu> 容器,并使用一个插槽(slot)来显示菜单标题。
- 组件接着递归地调用自己 <recursive-menu :menus="item.children" /> 来渲染子菜单。这是递归的关键步骤,因为它允许组件无限制地渲染任意深度的菜单结构。

5. 递归调用:对于每个子菜单项,步骤 3 和 4 会重复执行,直到渲染完所有层级的菜单。
 

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3是一个流行的前端框架,具有高效的渲染和响应能力。antd是一个基于Vue的UI组件库,提供了丰富的组件和样式。Vite是一个新的打包工具,具有更快的启动和热更新速度。 搭建一个后台项目,可以使用以下步骤: 1. 安装Node.js和npm,确保全局安装了@vue/cli。 2. 使用命令行工具创建一个新的Vue3项目:vue create my-project。 3. 选择手动配置,并选择Babel,Router,CSS Pre-processors,ESLint和Linter / Formatter。 4. 安装antd:npm install ant-design-vue@next。 5. 在src/main.js中引入antd的样式和组件:import { createApp } from 'vue'; import App from './App.vue'; import Antd from 'ant-design-vue'; import 'ant-design-vue/dist/antd.css'; 6. 在创建应用程序之前使用Antd组件:const app = createApp(App); app.use(Antd); app.mount('#app'); 7. 使用vite创建一个新的项目文件夹:mkdir my-project && cd my-project。 8. 在项目文件夹中初始化npm:npm init -y。 9. 安装vite:npm install vite。 10. 创建vite配置文件:npx create-vite。 11. 安装其他依赖:npm install axios vuex。 12. 在src/main.js中引入antd的样式和组件:import { createApp } from 'vue'; import App from './App.vue'; import Antd from 'ant-design-vue'; import 'ant-design-vue/dist/antd.css'; 13. 在创建应用程序之前使用Antd组件:const app = createApp(App); app.use(Antd).use(router).use(store).mount('#app')。 14. 运行开发服务器:npm run dev。 这样,你就成功搭建了一个使用Vue3、antd和vite的后台项目。你可以根据项目需求进行开发,并根据需要引入和使用更多的antd组件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值