利用递归组件动态渲染下拉菜单

自己想手搭一个vue3+ts的后台管理项目,在构建导航栏的时候,发现根据路由权限信息动态配置导航栏,之前的vue2实现方案比较复杂于是自己利用递归组件实现导航栏

1.首先创建路由

export const constantRoute = [
  {
    path: '/login',
    component: () => import('@/views/login/index.vue'),
    name: 'login',
    meta: {
      title: '登录',
      hidden: true,
    },
  },
  {
    path: '/',
    component: () => import('@/layout/index.vue'),
    name: 'layout',
    meta: {
      title: '首页',
      hidden: false,
    },
    children: [
      {
        path: '/home',
        component: () => import('@/views/home/home.vue'),
        name: 'home',
        meta: {
          title: '首页',
          hidden: false,
        },
      },
      {
        path: '/home',
        component: () => import('@/views/home/home.vue'),
        name: 'home',
        meta: {
          title: '首页',
          hidden: false,
        },
      },
    ],
  },
  {
    path: '/404',
    component: () => import('@/views/404/index.vue'),
    name: '404',
    meta: {
      title: '404',
      hidden: true,
    },
  },
  {
    path: '/:pathMatch(.*)*',
    redirect: '/404',
    name: 'Any',
    meta: {
      title: '任意路由',
      hidden: true,
    },
  },
]

2.将路由信息引入store,后期可进行持续化存储

// 引入路由
import { constantRoute } from '@/router/routes'
// 创建用户相关的仓库
import { defineStore } from 'pinia'
const userStore = defineStore('user', {
  state: () => {
    return {
      token: localStorage.getItem('TOKEN'),
//导航栏路由
      menuRoutes: constantRoute
    }
  },
  actions: {
    // 用户登陆方法
    userLogin(token: any) {
      console.log(token)
      userStore().token = token
      localStorage.setItem('TOKEN', token)
    },
  },
  getters: {},
})
// 对外暴露
export default userStore

2.创建一个导航栏组件

<!--  -->
<template>
  <!-- <div class="">{{ menuList }}</div> -->
<!-- 循环menuList菜单路由的列表 -->
  <div v-for="(item, index) in menuList" :key="index">
    <el-sub-menu :index="item.path" v-if="item.children && !item.meta.hidden">
      <template #title>{{ item.meta.title }}</template>
      <Menu :menuList="item.children"></Menu>
    </el-sub-menu>
    <el-menu-item :index="item.path" v-if="!item.meta.hidden && !item.children">
      <!-- <el-icon><icon-menu /></el-icon> -->
      <span>{{ item.meta.title }}</span>
    </el-menu-item>
  </div>
</template>

<script lang="ts" setup>
import { onMounted } from 'vue'
defineProps({
  menuList: {
    type: Array,
    // eslint-disable-next-line vue/require-valid-default-prop
    default: [],
  },
})

onMounted(() => {})
</script>
<!-- 嵌套路由需要再建个script导出Menu-->
<script lang="ts">
export default {
  // eslint-disable-next-line vue/no-reserved-component-names
  name: 'Menu',
}
</script>
<style lang="less" scoped></style>

3.在layout页面引入菜单栏

<template>
  <div class="layout_container">
    <div class="layout_slider">
      <logo></logo>
      <div>
        <el-scrollbar class="nav">
          <el-menu text-color="white" background-color="$base-menu-background">
//引入menu菜单组件
            <menuNav :menuList="userStores.menuRoutes"></menuNav>
          </el-menu>
        </el-scrollbar>
      </div>
    </div>
    <div class="layout_tabbar"></div>
    <div class="layout_main"></div>
  </div>
</template>

<script lang="ts" setup>
import logo from './logo/index.vue'
import menuNav from './menu/index.vue'
import userStore from '@/store/modules/user'
let userStores = userStore()
</script>
<style scoped lang="scss">
.layout_container {
  width: 100vw;
  height: 100vh;
  background-color: w;
}

.layout_slider {
  width: $base-menu-width;
  height: 100%;
  background-color: $base-menu-background;
}

.layout_tabbar {
  position: fixed;
  top: 0;
  left: $base-menu-width;
  width: calc(100% - $base-menu-width);
  height: $base-tabbar-height;
  background-color: #c111cc;
}

.layout_main {
  position: fixed;
  top: $base-tabbar-height;
  left: $base-menu-width;
  background-color: #0000;
  width: calc(100% - $base-menu-width);
  height: calc(100% - $base-tabbar-height);
  padding: $base-main-padding;
  overflow: auto;
}

.nav {
  height: calc(100vh - $base-tabbar-height);
  el-menu {
    border-right: 0px;
  }
}

.scrollbar-demo-item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 50px;
  margin: 10px;
  text-align: center;
  border-radius: 4px;
  background: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在以上模板中使用递归组件渲染多级表头,可以对表头数据进行递归处理,并在递归组件内部调用自身。下面是修改后的示例: ```vue <template> <table class="multi-level-table"> <thead> <tr> <template v-for="header in headers"> <recursive-header :header="header" :key="header.label" /> </template> </tr> </thead> <tbody> <tr v-for="row in rows" :key="row.id"> <td v-for="cell in row.cells" :key="cell.id"> {{ cell.content }} </td> </tr> </tbody> </table> </template> <script> export default { props: { headers: { type: Array, required: true }, rows: { type: Array, required: true } } }; </script> <style scoped> .multi-level-table th, .multi-level-table td { padding: 8px; border: 1px solid #ccc; } </style> <template id="recursive-header-template"> <th :colspan="header.colspan" :rowspan="header.rowspan"> {{ header.label }} <template v-if="header.children"> <tr> <template v-for="subHeader in header.children"> <recursive-header :header="subHeader" :key="subHeader.label" /> </template> </tr> </template> </th> </template> <script> Vue.component('recursive-header', { template: '#recursive-header-template', props: { header: { type: Object, required: true } } }); </script> ``` 在这个示例中,我们定义了一个名为 `recursive-header` 的递归组件,用于渲染多级表头。在组件模板中,我们根据传入的 `header` 对象渲染对应的表头单元格,并在单元格内部判断是否存在子级表头。如果存在子级表头,则再次调用递归组件渲染子级表头。 在主组件的模板中,我们使用 `v-for` 指令遍历 `headers` 数组,并在循环中使用 `<recursive-header>` 组件渲染多级表头。 这样,无论多少级的表头数据都可以通过递归组件进行渲染,实现了多级不规则表头的展示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值