用多少眼泪才能让你相信 发表于 2022-6-25 06:31:50

vue3+Element采用递归调用封装导航栏

vue3+Element采用递归调用封装导航栏

效果预览

https://img-blog.csdnimg.cn/fc89da0cb5504d5592f59ec094424b46.gif
模拟数据


[*]数据来源有很多,可以是自己写死的,也可以是后端调用得到的,也可以从别的组件中拿到
[*]这里采用从路由中拿
[*]定义数据源src/router/module.js/
const Login = () => import('../views/Login/Login.vue');
const Layout = () => import('../layout/layout.vue');
const Home = () => import('../views/Home.vue');
const User = () => import('../views/About.vue');
const Avatar = () => import('../views/Users/Avatar.vue');
const Password = () => import('../views/Users/Password.vue');

const routes = [
{
    path: '/',
    redirect: '/home',
},
{
    path: '/',
    name: 'Layout',
    component: Layout,
    meta: {
      permission: true,
    },
    children: [
      {
      path: '/home',
      name: 'Home',
      component: Home,
      meta: {
          title: '首页',
          icon: '', // iconfont图标
          inSide: true,
      },
      },
      {
      path: '/user',
      name: 'User',
      component: User,
      meta: {
          title: '个人中心',
          icon: '',
      },
      children: [
          {
            path: '/user/avatar',
            name: 'Avatar',
            component: Avatar,
            meta: {
            title: '修改头像',
            },
            children: [
            {
                path: '/setUp/avatar',
                name: 'setUp',
                component: Avatar,
                meta: {
                  title: '暂无',
                },
            },
            ],
          },
          {
            path: '/user/password',
            name: 'Password',
            component: Password,
            meta: {
            title: '修改密码',
            },
          },
      ],
      },
      {
      path: '/setUp',
      name: 'SetUp',
      meta: {
          title: '系统设置',
          icon: '',
      },
      children: [
          {
            path: '/setUp/avatar',
            name: 'setUp',
            component: Avatar,
            meta: {
            title: '暂无',
            },
          },
          {
            path: '/setUp/avatar',
            name: 'setUp',
            component: Avatar,
            meta: {
            title: '暂无',
            },
          },
      ],
      },
    ],
},

{
    path: '/login',
    name: 'Login',
    component: Login,
},
];
export default routes; 递归实现导航栏渲染



[*]对于导航栏渲染难点在于不知道有多少层级的导航,可能一级也可能两级或者更多
[*]为了方便采用两个组件父组件aside.vue与子组件subAside.vue渲染导航
[*]这时候就需要采用递归的方式

[*]首先判断哪些数据需要渲染,需要的拿出来
[*]判断是否有子节点需要渲染

[*]有子节点,递归调用子组件本身
[*]没有子节点,返回导航项进行渲染


父组件aside.vue

<template>
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px">
    <el-radio-button :label="false">expand</el-radio-button>
    <el-radio-button :label="true">collapse</el-radio-button>
</el-radio-group>
<el-menu
      default-active="2"
      class="el-menu-vertical-demo"
      :collapse="isCollapse"
      select="handleSelect"
      router
      unique-opened
>
   
    <SubAside :isCollapse="isCollapse" v-for="(item,index) in navs" :key="item.path" :menu="item" :index="item.path" />
</el-menu>

</template> 父组件处理后的用于渲染的数据
[
        {
                component: () => import('/src/views/Home.vue')
                meta: {title: '首页', icon: '', inSide: true}
                name: "Home"
                path: "/home"
        },
        {
                component: () => import('/src/views/About.vue')
                meta: {title: '个人中心', icon: ''}
                name: "User"
                path: "/user"
                chilren:[
                {
                        children: [{…}]
                        component: () => import('/src/views/Users/Avatar.vue?t=1655544364909')
                        meta: {title: '修改头像'}
                        name: "Avatar"
                        path: "/user/avatar"
                },
                {
                        component: () => import('/src/views/Users/Password.vue')
                        meta: {title: '修改密码'}
                        name: "Password"
                        path: "/user/password"
                }
                ]
        },
        {
                meta: {title: '系统设置', icon: ''}
                name: "SetUp"
                path: "/setUp"
                chilren:[
                {
                        component: () => import('/src/views/Users/Avatar.vue?t=1655544364909')
                        meta: {title: '暂无'}
                        name: "setUp"
                        path: "/setUp/avatar"
                },
                {
                        component: () => import('/src/views/Users/Avatar.vue?t=1655544364909')
                        meta: {title: '暂无'}
                        name: "setUp"
                        path: "/setUp/avatar"
                }
                ]
        }
] 子组件subAside.vue

<template>
   
    <el-sub-menu :index="menu.path" v-if="menu?.children">
      <template #title>
            <el-icon v-html="menu?.meta.icon"></el-icon>
            {{menu?.meta.title}}
      </template>
      
      <SubAside v-for="item in menu.children" :menu="item" :isCollapse="isCollapse"/>
    </el-sub-menu>
   
    <el-menu-itemv-else:index="menu?.path">
            <el-icon v-html="menu?.meta.icon"></el-icon>
            {{menu?.meta.title}}
    </el-menu-item >

</template>
    配置


[*]版本
"vue": "^3.2.25",
"element-plus": "^2.2.6",
[*]main.ts中配置
import { createApp } from 'vue';
import App from './App.vue';
// import 'virtual:windi.css';
import router from './router/index';
/**
* 引入elment
*/
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import './styles/dark/css-vars.css'


// 引入 Pinia 状态管理工具
import pinia from './stores'

const app=createApp(App)
/**
* 全局注册组件
*/
import SubAside from './components/subAside.vue'
app.component('SubAside', SubAside)


// 注册Element全局可用
app.use(ElementPlus).use(router).use(pinia).mount('#app');
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: vue3+Element采用递归调用封装导航栏