vue3中利用路由信息渲染菜单栏

1. 创建路由时将路由信息对象进行抽离

将路由信息对象单独抽离到router/routes.ts文件

关键:利用路由元信息 meta**,定义3个属性**

  1. hidden:控制当前路由是否显示在菜单栏中
  2. title:菜单拦名称
  3. icon:对应菜单名称前面的图标
TypeScript 复制代码
//对外暴露配置路由(常量路由)
export const constantRout = [
  {
    path: '/screen',
    component: () => import('@/views/screen/index.vue'),
    name: 'Screen',
    meta: {
      hidden: false,
      title: '数据大屏',
      icon: 'Platform',
    },
  },
    {
    path: '/acl',
    component: () => import('@/layout/index.vue'),
    name: 'Acl',
    meta: {
      hidden: false,
      title: '权限管理',
      icon: 'Lock',
    },
    children: [
      {
        path: '/acl/user',
        component: () => import('@/views/acl/user/index.vue'),
        name: 'User',
        meta: {
          hidden: false,
          title: '用户管理',
          icon: 'User',
        },
      },
      {
        path: '/acl/role',
        component: () => import('@/views/acl/role/index.vue'),
        name: 'Role',
        meta: {
          hidden: false,
          title: '角色管理',
          icon: 'UserFilled',
        },
      },
      {
        path: '/acl/permission',
        component: () => import('@/views/acl/permission/index.vue'),
        name: 'Permission',
        meta: {
          hidden: false,
          title: '菜单管理',
          icon: 'Monitor',
        },
      },
    ],
  },
]

router/index.ts文件引入router.ts文件

TypeScript 复制代码
import { createRouter, createWebHashHistory } from 'vue-router'
import { constantRoute } from './routes'
//创建路由器
const router = createRouter({
  //路由模式hash
  history: createWebHashHistory(),
  routes: constantRoute,
  //滚动行为
  scrollBehavior() {
    return {
      left: 0,
      top: 0,
    }
  },
})
export default router

2. 将路由信息对象挂载到pinia仓库中

将路由信息对象挂载到pinia仓库中,是为了数据共享,供组件使用

TypeScript 复制代码
//引入路由(常量路由)
import { constantRoute } from '../../router/routes'
const useUserStore = defineStore('User', {
  state: (): userState => {
    return {
      token: GET_TOKEN(),
      // 存储路由信息用来遍历生成菜单结构
      menuRoutes: constantRoute, //仓库存储生成菜单需要数组(路由)
    }
  },
}

完成将路由信息挂载到pinia仓库中

3. 在组件中通过路由信息对象渲染菜单

Menu是封装的组件,接收父组件传递的userStore.menuRoutes也就是存放在pinia仓库中的路由信息对象

TypeScript 复制代码
 <!-- 展示菜单区域 -->
      <el-scrollbar class="scrllbar">
        <el-menu background-color="#001529" text-color="white">
          <!-- 根据路由动态生成菜单 -->
          <Menu :menuList="userStore.menuRoutes"></Menu>
        </el-menu>
      </el-scrollbar>

在子组件Menu中声明接收:

TypeScript 复制代码
//通过props接收父组件传递的路由组件信息
defineProps(['menuList'])

Menu组件完整写法:

思路:通过路由信息对象中的children属性判断是否有子路由,如果有子路由,则继续判断子路由的个数,从而进行对应的判断处理

TypeScript 复制代码
<template>
  <!-- 根据路由来遍历左侧菜单展示信息 -->
  <template v-for="(item, index) in menuList" :key="item.path">
    <!-- 没有子路由 -->
    <template v-if="!item.children">
      <el-menu-item
        v-if="!item.meta.hidden"
        :index="item.path"
        @click="goRoute"
      >
        <template #title>
          <el-icon>
            <component :is="item.meta.icon"></component>
          </el-icon>
          <span>{{ item.meta.title }}</span>
        </template>
      </el-menu-item>
    </template>
    <!-- 有子路由但是只有一个 -->
    <template v-else-if="item.children && item.children.length == 1">
      <el-menu-item
        v-if="!item.children[0].meta.hidden"
        :index="item.children[0].path"
        @click="goRoute"
      >
        <template #title>
          <el-icon>
            <component :is="item.children[0].meta.icon"></component>
          </el-icon>
          <span>{{ item.children[0].meta.title }}</span>
        </template>
      </el-menu-item>
    </template>
    <!-- 有子路由且个数大于一个 -->
    <template v-if="item.children && item.children.length > 1">
      <el-sub-menu :index="item.path">
        <template #title>
          <el-icon>
            <component :is="item.meta.icon"></component>
          </el-icon>
          <span>{{ item.meta.title }}</span>
        </template>
        <Menu :menuList="item.children"></Menu>
      </el-sub-menu>
    </template>
  </template>
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'

//通过props接收父组件传递的路由组件信息
defineProps(['menuList'])
let $router = useRouter()
const goRoute = (vc: any) => {
  //路由跳转
  $router.push(vc.index)
}
</script>
<script lang="ts">
// 当子路由个数大于等于一个时,并且或许子路由还有后代路由时。
// 这里我们使用了递归组件。递归组件需要命名(另外使用一个script标签,vue2格式)。
export default {
  name: 'Menu',
}
</script>
<style scoped lang="scss">
</style>

注意:在Menu组件中使用了Menu(递归组件),递归组件需要命名(另外使用一个script标签,vue2格式)。

TypeScript 复制代码
export default {
  name: 'Menu',
}

注意:在el-menu-item组件中有一个click方法,对应一个函数,由element提供,会接收一个组件实例参数,并配合useRouter进行路由跳转

TypeScript 复制代码
const goRoute = (vc: any) => {
  //路由跳转
  $router.push(vc.index)
}
相关推荐
轻口味4 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王39 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀1 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6414 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js