第十节:动态侧边栏菜单(根据路由 meta 自动渲染菜单)

第十节:动态侧边栏菜单(根据路由 meta 自动渲染菜单)

当前写死 el‑menu‑item,本节改成循环渲染;读取路由配置meta.title生成侧边栏菜单,为后续后端返回动态菜单做铺垫。

步骤 1:新建 src/layout/components/SidebarMenu.vue

把菜单抽成独立组件

复制代码
<template>
  <el-menu
    :collapse="appStore.sidebarCollapse"
    mode="vertical"
    router
    background-color="#304156"
    text-color="#bfcbd9"
    active-text-color="#409eff"
  >
    <template v-for="item in menuList" :key="item.path">
      <el-menu-item v-if="!item.children" :index="item.childrenPath">
        <el-icon><House /></el-icon>
        <template #title>{{ item.meta.title }}</template>
      </el-menu-item>
    </template>
  </el-menu>
</template>

<script setup>
import { computed } from 'vue'
import { useAppStore } from '@/stores/app'
import { asyncRoutes } from '@/router'

const appStore = useAppStore()

// 处理路由,提取菜单
const menuList = computed(() => {
  const res = []
  asyncRoutes.forEach(route => {
    if(route.children && route.children.length>0){
      const child = route.children[0]
      res.push({
        path: route.path,
        childrenPath: `${route.path}/${child.path}`,
        meta: child.meta
      })
    }
  })
  return res
})
</script>

步骤 2:修改 src/layout/index.vue,替换写死的 el‑menu

复制代码
<template>
  <el-container class="layout-container">
    <!-- 侧边栏 -->
    <el-aside :width="appStore.sidebarCollapse ? '64px' : '210px'" class="sidebar">
      <div class="logo">
        <span v-if="!appStore.sidebarCollapse">管理系统</span>
      </div>
      <!-- 使用抽离的菜单组件 -->
      <SidebarMenu />
    </el-aside>

    <el-container>
      <!-- 顶部头部 -->
      <el-header class="layout-header">
        <div class="header-left">
          <el-button
            :icon="Expand"
            circle
            @click="appStore.toggleSidebar()"
          ></el-button>
        </div>
        <div class="header-right">
          <el-dropdown @command="handleCommand">
            <span class="user-info">
              <el-icon><User /></el-icon>
              {{ userStore.username }}
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item command="logout">退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </div>
      </el-header>

      <!-- 主内容区域 -->
      <el-main class="layout-main">
        <router-view />
      </el-main>
    </el-container>
  </el-container>
</template>

<script setup>
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { useRouter } from 'vue-router'
import { House, Expand, User } from '@element-plus/icons-vue'
// 引入菜单组件
import SidebarMenu from './components/SidebarMenu.vue'

const appStore = useAppStore()
const userStore = useUserStore()
const router = useRouter()

const handleCommand = async (command) => {
  if (command === 'logout') {
    userStore.logout()
    ElMessage.success('退出成功')
    router.push('/login')
  }
}
</script>

<style scoped>
.layout-container {
  height: 100vh;
}
.sidebar {
  background-color: #304156;
  transition: width 0.3s;
}
.logo {
  height: 50px;
  line-height: 50px;
  text-align: center;
  color: #fff;
  font-size: 16px;
  background-color: #263445;
}
.layout-header {
  background: #fff;
  border-bottom: 1px solid #e6e6e6;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 16px;
}
.user-info {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap:4px;
}
.layout-main {
  background-color: #f5f7fa;
  padding: 16px;
  overflow: auto;
}
</style>

步骤 3:新增一个测试业务路由,验证动态菜单生效

修改 src/router/index.jsasyncRoutes,增加【系统管理】页面

复制代码
export const asyncRoutes = [
  {
    path: '/dashboard',
    component: Layout,
    redirect: '/dashboard/index',
    children: [
      {
        path: 'index',
        name: 'Dashboard',
        component: () => import('@/views/dashboard/index.vue'),
        meta: { title: '首页看板' }
      }
    ]
  },
  //新增测试菜单
  {
    path: '/system',
    component: Layout,
    redirect: '/system/user',
    children: [
      {
        path: 'user',
        name: 'UserManage',
        component: () => import('@/views/system/user.vue'),
        meta: { title: '用户管理' }
      }
    ]
  }
]

新建页面 src/views/system/user.vue

复制代码
<template>
  <PageCard title="用户管理">
    <el-table :data="tableData" border>
      <el-table-column prop="id" label="ID"></el-table-column>
      <el-table-column prop="name" label="用户名"></el-table-column>
    </el-table>
  </PageCard>
</template>

<script setup>
const tableData = [
  {id:1,name:'admin'},
  {id:2,name:'test'}
]
</script>

✅第十节测试

  1. 重启 pnpm dev,登录系统
  2. 侧边栏自动渲染两条菜单:首页看板用户管理
  3. 点击菜单,正常跳转对应页面 ✔
  4. 侧边栏折叠展开功能依旧正常,控制台无红色报错。

现在菜单不再写死,全部读取路由meta.title渲染;下一节做面包屑导航 + tag‑view 标签页(仿若依多标签)

相关推荐
浪兎兎39 分钟前
Vue CLI笔记
前端·vue.js·笔记
前端炒粉1 小时前
容器预热预跳转方案
前端·vue.js·性能优化
tt一点通1 小时前
前端常用设计模式大全
前端·vue.js
ttwuai1 小时前
Go 后台管理系统组件库文档怎么写,才不会坑后续维护?
开发语言·javascript·golang
学长毕业设计1 小时前
基于SpringBoot的校园爱心志愿管理系统(源码+文档+讲解视频)
vue.js·spring boot·后端
光影少年1 小时前
react navite调试方案:Flipper、远程调试
前端·javascript·react native·react.js·前端框架
海兰1 小时前
【应用】基于 Next.js 16 + Python mplfinance的金融K线图与技术指标可视化平台(二)
javascript·python·金融
雪芽蓝域zzs2 小时前
第五节:Vue‑Router4 路由配置,布局嵌套路由
前端·javascript·vue.js
雪芽蓝域zzs2 小时前
第十二节:完整用户管理 CRUD 页面(表格分页、新增 / 编辑弹窗、删除、Mock 接口)
前端·javascript·vue.js