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)
}
相关推荐
10年前端老司机3 分钟前
React 受控组件和非受控组件区别和使用场景
前端·javascript·react.js
夏晚星4 分钟前
vue实现微信聊天emoji表情
前端·javascript
停止重构5 分钟前
【方案】前端UI布局的绝技,响应式布局,多端适配
前端·网页布局·响应式布局·grid布局·网页适配多端
極光未晚6 分钟前
TypeScript在前端项目中的那些事儿:不止于类型的守护者
前端·javascript·typescript
ze_juejin7 分钟前
Vue3 + Vite + Ant Design Vue + Axios + Pinia 脚手架搭建
前端·vue.js
lichenyang4539 分钟前
React项目(移动app)
前端
用户618482402195110 分钟前
Vue-library-start,一个基于Vite的vue组件库开发模板
前端
美团技术团队21 分钟前
报名 | 美团技术沙龙第86期:多业务场景下,美团如何做性能优化
前端
Rrvive1 小时前
localhost 和 127.0.0.1 的核心区别
前端
蓝倾1 小时前
如何使用Python通过API接口批量抓取小红书笔记评论?
前端·后端·api