vue3+Element uses recursive calls to encapsulate the navigation bar

Hits: 0

vue3+Element uses [recursive calls to] encapsulate the navigation bar

Effect preview

Simulation data

  1. There are many data sources, which can be written to death, or obtained by back-end calls, or obtained from other components
  2. Here is taken from the route
  3. Define the data source 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: {
          inSide: true,
        },
      },
      {
        path: '/user',
        name: 'User',
        component: User,
        meta: {
          icon: '<span class="iconfont icon-yonghuzhongxin1"/>',
        },
        children: [
          {
            path : '/user/avatar' ,
             name : 'Avatar' ,
             component : Avatar,
             meta : {
               title : 'Modify Avatar' ,
            },
            children: [
              {
                path: '/setUp/avatar',
                name: 'setUp',
                component: Avatar,
                meta: {
                },
              },
            ],
          },
          {
            path : '/user/password' ,
             name : 'Password' ,
             component : Password,
             meta : {
               title : 'Change password' ,
            },
          },
        ],
      },
      {
        path: '/setUp',
        name: 'SetUp',
        meta: {
          icon: '<span class="iconfont icon-celveguanli"/>',
        },
        children: [
          {
            path: '/setUp/avatar',
            name: 'setUp',
            component: Avatar,
            meta: {
            },
          },
          {
            path: '/setUp/avatar',
            name: 'setUp',
            component: Avatar,
            meta: {
            },
          },
        ],
      },
    ],
  },

  {
    path: '/login',
    name: 'Login',
    component: Login,
  },
];
export default routes;

Recursive implementation of navigation bar rendering

  • The difficulty in rendering the navigation bar is that you don’t know how many levels of navigation there are, maybe one level or two levels or more.
  • In order to facilitate the use of two components parent component aside.vue and child component subAside.vue rendering navigation
  • In this case, it is necessary to use a recursive method
    • First, determine which data needs to be rendered and take out what needs to be rendered.
    • Determine if there are child nodes that need to be rendered
      • Has child nodes, recursively calls the child component itself
      • No child nodes, return to navigation item for rendering

Parent component 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 
  > 
    <!-- Pass each item of the rendered navigation to the sub-component for rendering, item represents each item to be rendered --> 
    < SubAside  :isCollapse = "isCollapse"  v-for = "(item,index) in navs"  :key = "item.path"  :menu = "item"  :index = "item.path" /> 
  </ el-menu >

</template>

< script  lang = "ts"  setup > import { ref } from 'vue' ;
 import router from '../router/module' ;
 const navs =router.filter( ( item ) => item.meta?.permission)[ 0 ].children // Filter to get the data console .log(navs);



const isCollapse = ref( true ); // Whether to collapse, not collapse by default

</script>

<style lang="scss" scoped></style>

Data processed by the parent component for rendering

[
    {
        component: () => import('/src/views/Home.vue')
        name: "Home"
        path: "/home"
    },
    {
        component: () => import('/src/views/About.vue')
        meta: {title: 'Personal Center' , icon: '<span class="iconfont icon-yonghuzhongxin1"/>' }
        name: "User"
        path: "/user"
        chilren:[
        {
            children: [{…}]
            component: () => import('/src/views/Users/Avatar.vue?t=1655544364909')
            meta: {title: 'Modify Avatar' }
            name: "Avatar"
            path: "/user/avatar"
        },
        {
            component: () => import('/src/views/Users/Password.vue')
            meta: {title: 'Change password' }
            name: "Password"
            path: "/user/password"
        }
        ]
    },
    {
        meta: {title: 'System Settings' , icon: '<span class="iconfont icon-celveguanli"/>' }
        name: "SetUp"
        path: "/setUp"
        chilren:[
        {
            component: () => import('/src/views/Users/Avatar.vue?t=1655544364909')
            meta: {title: 'Nothing' }
            name: "setUp"
            path: "/setUp/avatar"
        },
        {
            component: () => import('/src/views/Users/Avatar.vue?t=1655544364909')
            meta: {title: 'Nothing' }
            name: "setUp"
            path: "/setUp/avatar"
        }
        ]
    }
]

Subcomponent subAside.vue

< template > 
    <!-- have child nodes render this --> 
    < el-sub-menu  :index = "menu.path"  v-if = "menu?.children" > 
        < template # title > 
            < el-icon  v -html = "menu?.meta.icon" > </ el-icon > 
            < span > {{menu?.meta.title}} </ span > 
        </ template > 
        <!-- recursively calls itself, the component in Globally registered in index.ts --> 
        < SubAside  v-for = "item in menu.children" :menu="item"  :isCollapse = "isCollapse" /> 
    </ el-sub-menu > 
    <!-- no child nodes render this --> 
    < el-menu-item   v-else   :index = "menu?.path" > 
            < el-icon  v-html = "menu?.meta.icon" > </ el-icon > 
            < span  slot = "title" > {{menu?.meta.title}} </ span > 
    </ el-menu -item >

</template>

< script  lang = "ts"  setup > import { ref } from "vue" // Get the value passed in by the parent component


defineProps({
  isCollapse:Boolean,
  menu:Object
})


</script>

<style lang="scss" scoped>

</style>

configure

  1. Version

"vue": "^3.2.25",
 "element-plus": "^2.2.6",

  1. Configuration in main.ts

import { createApp } from 'vue';
import App from './App.vue';
// import 'virtual:windi.css';
import router from './router/index';
/**
 * Introduce 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'


// Introduce Pinia state management tool 
import pinia from  './stores'

const app=createApp(App)
 /**
  * Globally register components
  */
import SubAside from './components/subAside.vue'
app.component('SubAside', SubAside)


// Register Element globally available 
app.use(ElementPlus).use(router).use(pinia).mount( '#app' );

Leave a Reply

Your email address will not be published.