Vue3中动态渲染菜单栏(TS)

本文介绍如何在Vue项目中利用路由文件动态生成左侧菜单栏,包括数据组织与使用Element Plus的Menu组件展示的方法。适用于一级菜单及多级菜单的动态渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:左侧的菜单栏渲染数据从路由文件中获取并组织成我们想要的数据格式。

路由:router》index.ts

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'home',
    component: HomeView,
    redirect:"order",
    children: [
      {
        path: 'order',
        name: 'order',
        meta:{isShow:true,title:"订单列表"},
        component: () => import('../views/OrderList.vue'),
      },
      {
        path: 'user',
        name: 'user',
        meta:{isShow:true,title:"用户列表"},
        component: () => import('../views/UserList.vue'),
      },
    ]
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    path: '/login',
    name: 'login',
    component: () => import( '../views/Login.vue')
  }
]

渲染菜单:

1、组织数据:

<script lang="ts">
import { defineComponent } from "vue";
import { useRouter, useRoute } from "vue-router";
export default defineComponent({
  name: "HomeView",
  components: {},
  setup() {
    const router = useRouter();
    const route = useRoute();
    // 获取到isShow为true的路由列表动态渲染菜单
    const routerList = router.getRoutes().filter((v) => v.meta.isShow);
    return {
      routerList,
      active: route.path,
    };
  },
});
</script>

2、使用element-plus的Menu组件进行展示:

  • el-menu组件要开启路由模式:router
  • 要添加  <router-view />
    <el-container>
      <el-aside width="200px">
        <el-menu
          router
          active-text-color="#ffd04b"
          background-color="#545c64"
          class="el-menu-vertical-demo"
          :default-active="active"
          text-color="#fff"
        >
          <el-menu-item v-for="i in list" :key="i.path" :index="i.path">
            <el-icon><icon-menu /></el-icon>
            <span>{{ i.meta.title }}</span>
          </el-menu-item>
        </el-menu>
      </el-aside>
      <el-main>
        <router-view />
      </el-main>
    </el-container>

效果:

此代码只适用一级菜单,多级菜单也是这个思路组织好数据然后再渲染。

这个其实不完全算是动态的路由,动态的路由其实应该是后端根据当前用户信息返回的路由。

可以在路由拦截里从后台获取路由数据并添加到路由里:

// 路由拦截
router.beforeEach(async to => {
  const token:string | null = localStorage.getItem('token')
  if (!token && to.path !== '/login') {
    // 若没有登录且去的不是登录页面,强制用户登录
    return '/login'
  } else if (token && to.path !== '/login/') {
    // 如果登陆过了且不去登录页面,并且之前没有加载过菜单,那么要加载菜单
    if (router.getRoutes().length === 3) {
      // 请求后台接口获取路由【同步】
      let routerData:any = await getRouter()
      routerData = routerData.data
      routerData.forEach((v:any) => {
        const routerObj:RouteRecordRaw = {
            path:v.path,
            name:v.name,
            meta: v.meta,
            component:()=>import(/* webpackChunkName: "[request]" */ `../views/${v.path}.vue`)
        }
        //将路由节点添加到home的children中
        router.addRoute("home",routerObj)
      })
      router.replace(to.path)
    }
  } else if (token && to.path === "/login") {
    return '/'
  }
})

### 实现基于用户角色的动态菜单栏Vue3 和 Pinia 的组合中,通过使用 `Pinia` 来管理状态可以有效地处理不同用户的权限差异,并据此动态调整菜单项。下面介绍一种方法来实现这一目标。 #### 创建存储库用于保存用户信息和菜单列表 首先定义一个名为 `authStore.js` 或者其他合适名称的文件作为 Pinia store: ```javascript import { defineStore } from &#39;pinia&#39;; export const useAuthStore = defineStore(&#39;auth&#39;, { state: () => ({ userRoles: [], // 用户的角色数组 menuItems: [] // 动态加载后的菜单条目集合 }), actions: { setRoles(roles) { this.userRoles = roles; }, async fetchMenu() { try { let response; if (this.userRoles.includes(&#39;admin&#39;)) { response = await axios.get(&#39;/api/admin-menus&#39;); } else { response = await axios.get(`/api/user/${this.userRoles}/menus`); } this.menuItems = response.data.menus || []; } catch(error){ console.error("Failed to load menus", error); } } } }); ``` 这段代码创建了一个简单的 Store,它包含了两个主要属性:一个是用来表示当前登录用户所拥有的角色;另一个是用来存放最终要展示给前端用户的菜单列表[^1]。 #### 组件内调用获取菜单逻辑 接着可以在 App.vue 或者任意合适的父级组件里初始化这个过程,在 mounted 生命周期钩子函数里面触发一次菜单拉取操作: ```html <template> <!-- 假设这里是放置 ElMenu 组件的地方 --> </template> <script setup lang="ts"> import { onMounted, ref } from "vue"; import { useAuthStore } from "@/stores/auth"; const authStore = useAuthStore(); onMounted(() => { authStore.fetchMenu(); // 当组件被装载时立即尝试获取最新的菜单结构 }); // 渲染菜单的方法可以根据实际情况编写... </script> ``` 此部分展示了如何利用 Composition API 风格的方式引入之前定义好的 AuthStore 并在其生命周期事件发生之时执行相应的业务逻辑——即向服务器请求对应于特定身份下的导航链接[^2]。 #### 构建视图层以响应式更新 UI 最后一步就是构建实际可见的部分了。假设已经安装好了 Element Plus 库,则可以直接借用其内置组件完成这部分工作: ```html <template> <el-menu :default-active="$route.path" router class="el-menu-vertical-demo"> <MenuItem v-for="(item,index) in visibleMenus" :key="index" :menuData="item"/> </el-menu> </template> <script setup lang="ts"> import { computed } from &#39;vue&#39;; import MenuItem from &#39;./components/MenuItem.vue&#39;; // 自定义菜单项组件路径可能有所不同 import { useAuthStore } from &#39;@/stores/auth&#39;; const authStore = useAuthStore(); const visibleMenus = computed(() => authStore.menuItems); </script> ``` 上述模板片段说明了怎样遍历由 Vuex 提供的数据源 (`visibleMenus`) ,并通过自定义组件 `<MenuItem>` 将每一项渲染出来。值得注意的是这里还应用了一些额外特性比如默认激活项(`$route.path`) 及路由模式(`router`)使得点击某个选项卡能够自动跳转至相应页面[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值