ant-design-vue 动态生成导航菜单(1~2级)

由于近来公司业务繁忙,以至于没时间去接着做antd的项目。emmm…后面应该还会忙些时间!

antd的路由导航还是有些坑的,对习惯了element的小伙伴来说不那么理想。这里先记录一下如何通过路由来动态生成1~2级导航菜单了(之后会出三级及以上导航菜单爬坑日志)。注: 此文为过渡文,没怎么上心,表达不明之处还请见谅,另外,欢迎打扰~~~~项目在线地址 (有用的话,记得给个start哦)

  1. antd的a-menu标签内部不能使用除template外的其他任何标签包裹 a-menu-item 以及 a-sub-menu标签,一旦使用就会报错!也因此没法组件化二级菜单(这里先不讲函数式组件)
  2. 既然是动态生成二级导航菜单,当然就不能使用定义路由、子路由的数组来维护,太繁琐,每次新增一个路由还得手动去添加。这样根本就算不得动态了。在这里博主参考的是花裤衩大佬的vue-element-admin开源项目所使用的方法。通过在定义路由的时候同时写入hidden(是否加入动态生成的导航菜单)以及meta(动态生成title及icon),代码如下:
{
     
  path: '/',
  component: Layout,
  redirect: '/dashboard',
  children: [
    {
     
      path: 'dashboard',
      name: 'Home',
      component: () => import('@/views/dashboard/index'),
      meta: {
      title: 'Dashboard', icon: 'user' }
    }
  ]
}
  1. 导航菜单(这里在后期有更新(在做三级及以上路由的时候有大幅更新),先放个最初版本的,在下一篇文章会贵出最终版)
<a-menu theme="dark" mode="inline" :selected-keys="currentSelectMenu" :open-keys="openKeys" @click="menuClick" @openChange="onOpenChange">
  <template v-for="item in routers">
    <template v-if="!item.hidden && item.children">
      
      <a-menu-item v-if="item.children.length === 1" :key="item.path === '/' ? `${item.path}${item.children[0].path}`: `${item.path}/${item.children[0].path}`">
        <a-icon :type="item.children[0] && item.children[0].meta && item.children[0].meta.icon" />
        <router-link style="display: inline-block" :to="{path: item.path === '/' ? `${item.path}${item.children[0].path}` : `${item.path}/${item.children[0].path}`}">
          {
    { generateTitle(item.children[0].meta.title) }}
        router-link>
      a-menu-item>
      
      <a-sub-menu v-else :key="item.path">
        <span slot="title">
          <a-icon :type="item.meta && item.meta.icon" />
          <span v-if="item.meta">{
    { generateTitle(item.meta.title) }}span>
        span>
        <template v-for="subItem in item.children">
          <a-menu-item v-if="!subItem.children" :key="item.path + '/' + subItem.path">
            <a-icon v-if="subItem.meta.icon" :type="subItem.meta && subItem.meta.icon" />
            <router-link style="display: inline-block" :to="item.path + '/' + subItem.path">
              {
    { generateTitle(subItem.meta.title) }}
            router-link>
          a-menu-item>
        template>
      a-sub-menu>
    template>
  template>
a-menu>

这里涉及到的a-menu属性啥的就不详细赘述了,官方文档挺好的(主要是表达能力着实不行…),这里说一下所用到的属性及事件吧。

  • selected-keys: 当前选中的菜单项,值的类型为字符串数组。这里主要用于刷新界面后保持选中的状态;
// 当前选中的菜单项(这里直接返回path即可)
currentSelectMenu() {
     
  return [this.$route.path]
}

open-keys:当前展开的 SubMenu 菜单项 key 数组,这里的key数组必须与父节点菜单的key值相对应。实现openKeys与父节点菜单的key的方法有很多,最初采用的是将其存入浏览器的sessionStorage(有些麻烦,后期在做三级菜单的时候移除了)。openChange:SubMenu 展开/关闭的回调,主要是为了控制当前submenu菜单是否展开/关闭;

// 通过菜单栏的点击事件menuClick将当前菜单的key存入sessionStorage
menuClick({
      item, key, keyPath }) {
     
  // length为1则说明没有子菜单
  if (keyPath.length === 1) {
     
    this.openKeys = []
    window.sessionStorage.clear()
  } else window.sessionStorage.setItem('open-menu-key', keyPath.pop()) // 将副路由存入sessionStorage,展开激活submenu菜单
},

// 在created生命周期获取,初始化展开submenu
const openKeys = window.sessionStorage.getItem('open-menu-key')
if (openKeys) this.openKeys = [openKeys]

// openChange:SubMenu 展开/关闭的回调,主要是为了控制当前submenu菜单是否展开/关闭
// 子菜单展开/关闭的回调
onOpenChange(openKeys) {
     
  const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
  this.openKeys = this.rootSubmenuKeys.indexOf(latestOpenKey) === -1 ? openKeys : latestOpenKey ? [latestOpenKey] : []
}

最后,附上全部代码

<template>
  <div class="sidebar-container">
    <a-layout-sider v-model="isCollapsed" :trigger="null" collapsible>
      <div class="logo" />
      <a-menu theme="dark" mode="inline" :selected-keys="currentSelectMenu" :open-keys="openKeys" @click="menuClick" @openChange="onOpenChange">
        <template v-for="item in routers">
          <template v-if="!item.hidden && item.children">
            
            <a-menu-item v-if="item.children.length === 1" :key="item.path === '/' ? `${item.path}${item.children[0].path}`: `${item.path}/${item.children[0].path}`">
              <a-icon :type="item.children[0] && item.children[0].meta && item.children[0].meta.icon" />
              <router-link style="display: inline-block" :to="{path: item.path === '/' ? `${item.path}${item.children[0].path}` : `${item.path}/${item.children[0].path}`}">
                {
    { generateTitle(item.children[0].meta.title) }}
              router-link>
            a-menu-item>
            
            <a-sub-menu v-else :key="item.path">
              <span slot="title">
                <a-icon :type="item.meta && item.meta.icon" />
                <span v-if="item.meta">{
    { generateTitle(item.meta.title) }}span>
              span>
              <template v-for="subItem in item.children">
                <a-menu-item v-if="!subItem.children" :key="item.path + '/' + subItem.path">
                  <a-icon v-if="subItem.meta.icon" :type="subItem.meta && subItem.meta.icon" />
                  <router-link style="display: inline-block" :to="item.path + '/' + subItem.path">
                    {
    { generateTitle(subItem.meta.title) }}
                  router-link>
                a-menu-item>
              template>
            a-sub-menu>
          template>
        template>
      a-menu>
    a-layout-sider>
  div>
template>

<script>
// 国际化导航菜单title
import {
       generateTitle } from './breadcrumb/index.js'
export default {
      
  name: 'SubMenu',
  props: {
      
    collapsed: [Boolean],
    routers: {
      
      type: Array,
      default: () => []
    }
  },
  data() {
      
    return {
      
      isCollapsed: false,
      onlyOneChild: null,
      openKeys: [''],
      rootSubmenuKeys: ['/form', '/about'] // submenu数组
    }
  },
  computed: {
      
    // 当前选中的菜单项
    currentSelectMenu() {
      
      return [this.$route.path]
    },
    router() {
      
      return this.$route.path
    }
  },
  watch: {
      
    collapsed: {
      
      handler: function(val) {
      
        this.isCollapsed = val
      }
    }
  },
  created() {
      
    // 获取当前副路由(需要展开)
    const openKeys = window.sessionStorage.getItem('open-menu-key')
    if (openKeys) this.openKeys = [openKeys]
  },
  methods: {
      
    generateTitle,
    // 点击菜单触发事件
    menuClick({
       item, key, keyPath }) {
      
      // length为1则说明没有子菜单
      if (keyPath.length === 1) {
      
        this.openKeys = []
        window.sessionStorage.clear()
      } else window.sessionStorage.setItem('open-menu-key', keyPath.pop()) // 将副路由存入sessionStorage,展开激活submenu菜单
    },
    // 子菜单展开/关闭的回调
    onOpenChange(openKeys) {
      
      const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
      this.openKeys = this.rootSubmenuKeys.indexOf(latestOpenKey) === -1 ? openKeys : latestOpenKey ? [latestOpenKey] : []
    }
  }
}
script>

<style lang="less" scoped>
.logo {
      
  height: 32px;
  background: rgba(255, 255, 255, 0.2);
  margin: 16px;
}
style>

你可能感兴趣的:(antd,vue,Vue,javaScript,javascript,vue.js,html5)