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

 更新时间:2022年06月20日 15:04:36   作者:鹏程933  
本文主要介绍了vue3+Element采用递归调用封装导航栏,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

效果预览

请添加图片描述

模拟数据

  • 数据来源有很多,可以是自己写死的,也可以是后端调用得到的,也可以从别的组件中拿到
  • 这里采用从路由中拿
  • 定义数据源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: '<span class="iconfont icon-shouye"/>', // iconfont图标
          inSide: true,
        },
      },
      {
        path: '/user',
        name: 'User',
        component: User,
        meta: {
          title: '个人中心',
          icon: '<span class="iconfont icon-yonghuzhongxin1"/>',
        },
        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: '<span class="iconfont icon-celveguanli"/>',
        },
        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
  >
    <!-- 将渲染导航每一项传给子组件渲染,item代表要渲染每一项 -->
    <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 // 过滤拿到数据
console.log(navs);

const isCollapse = ref(true); // 是否收起,默认不收起

</script>

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

父组件处理后的用于渲染的数据

[
	{
		component: () => import('/src/views/Home.vue')
		meta: {title: '首页', icon: '<span class="iconfont icon-shouye"/>', inSide: true}
		name: "Home"
		path: "/home"
	},
	{
		component: () => import('/src/views/About.vue')
		meta: {title: '个人中心', icon: '<span class="iconfont icon-yonghuzhongxin1"/>'}
		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: '<span class="iconfont icon-celveguanli"/>'}
		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>
            <span>{{menu?.meta.title}}</span>
        </template>
        <!-- 递归调用本身,该组件在index.ts中全局注册了 -->
        <SubAside v-for="item in menu.children" :menu="item" :isCollapse="isCollapse"/>
    </el-sub-menu>
    <!-- 没有子节点渲染这个 -->
    <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"
// 拿到父组件传入的值
defineProps({
  isCollapse:Boolean,
  menu:Object
})


</script>

<style lang="scss" scoped>

</style>

配置

版本

"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');

到此这篇关于vue3+Element采用递归调用封装导航栏实现的文章就介绍到这了,更多相关vue3 Element封装导航栏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • elementUI vue this.$confirm 和el-dialog 弹出框 移动 示例demo

    elementUI vue this.$confirm 和el-dialog 弹出框 移动 示例demo

    这篇文章主要介绍了elementUI vue this.$confirm 和el-dialog 弹出框 移动 示例demo,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • Vue中引入样式文件的方法

    Vue中引入样式文件的方法

    这篇文章主要介绍了Vue中引入样式文件的方法,需要的朋友可以参考下
    2017-08-08
  • 解决Vue大括号字符换行踩的坑

    解决Vue大括号字符换行踩的坑

    这篇文章主要介绍了解决Vue大括号字符换行踩的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 详解Vue CLI3 多页应用实践和源码设计

    详解Vue CLI3 多页应用实践和源码设计

    这篇文章主要介绍了详解Vue CLI3 多页应用实践和源码设计,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Vue生命周期实例分析总结

    Vue生命周期实例分析总结

    Vue的生命周期就是vue实例从创建到销毁的全过程,也就是new Vue()开始就是vue生命周期的开始。Vue实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom->渲染、更新->渲染、卸载等⼀系列过程,称这是Vue的⽣命周期
    2022-10-10
  • vue-photo-preview图片预览失效的问题及解决

    vue-photo-preview图片预览失效的问题及解决

    这篇文章主要介绍了vue-photo-preview图片预览失效的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • Vue-cli3中如何引入ECharts并实现自适应

    Vue-cli3中如何引入ECharts并实现自适应

    这篇文章主要介绍了Vue-cli3中如何引入ECharts并实现自适应,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • vue使用路由router-view的详细代码

    vue使用路由router-view的详细代码

    这篇文章主要介绍了vue使用路由router-view的相关知识,其原理就是采用 SPA(single-page-application) 模式,就是只有一个 Web 页面的应用,通过 router 来控制页面的刷新和迭代,感兴趣的朋友一起看看吧
    2023-12-12
  • 在 Vue3 中如何使用 styled-components

    在 Vue3 中如何使用 styled-components

    styled-components 的官方 Vue 版本目前已多年没有更新,而且只支持到 Vue2,那么,在 Vue3 中怎么才能使用到 styled-components 呢,下面给大家介绍在 Vue3 中使用 styled-components的相关知识,感兴趣的朋友跟随小编一起看看吧
    2024-05-05
  • Vue3之toRefs和toRef在reactive中的一些应用方式

    Vue3之toRefs和toRef在reactive中的一些应用方式

    这篇文章主要介绍了Vue3之toRefs和toRef在reactive中的一些应用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03

最新评论