用ANTD-Vue做管理页面的左侧菜单 需要在刷新后也能保持左侧菜单被选中和展开 且只能展开一个菜单

成品效果图

ant design vue 隐藏菜单 ant design vue 动态菜单_vue.js

1.在刷新后保持菜单选中

这个比较简单
ANTD的API中提供了一个defaultSelectedKeys参数

描述:初始选中的菜单项 key 数组
类型: string[] 
自己手动实验得知意思就是在数组中填入字符串 例如['key']
默认值为空

一级菜单和子菜单都有一个key属性,我后端返回的json数据中的router属性是每个菜单的路由跳转地址, 同时将这个地址赋值给菜单的key 这样点击菜单跳转后 用this.$route.path获取到的当前路由地址就和菜单的key一致了

在菜单标签中设置 defaultSelectedKeys属性指向this.$route.path即可完成在刷新后保持菜单选中

2.在刷新后如果当前选中的菜单是二级菜单则展开当前菜单的父菜单

可展开(有二级菜单)的一级菜单点击后会展开或收起 不会发生跳转

ANTD提供了两个api:

openKeys	当前展开的 SubMenu 菜单项 key 数组
defaultOpenKeys	初始展开的 SubMenu 菜单项 key 数组

两个api中的描述 一个是"当前" 另一个是"初始(默认)" ,试了半天后发现用defaultOpenKeys设置值后是只生效一次的 也就是说初始设置defaultOpenKeys的对应属性为空 等ajax请求到数据后再去设置,菜单就不会变化了,所以不能用这个

openKeys

看来只能用openKeys了,我又发现一个小问题,设置openKeys后手动点击其他没展开的菜单,菜单不会有变化 这样就得用到另一个API

openChange	展开/关闭的回调

每次点击可展开/收起的菜单时都会触发这个属性所对应的函数,设置openKeys后再配合openChange切换菜单即可解决问题

具体请看代码
VUE html代码部分(只截取了菜单部分)

<a-menu theme="dark" 
        :openKeys="openKeys" // 重点 当前展开的菜单
        mode="inline"
        @openChange="onOpenChange" // 重点 当可以展开的菜单被点击时
        :defaultSelectedKeys="defaultSelectedKeys" // 默认选中的菜单
        style="width: 100%"
       >
      <template v-for="item in menuList"> // 渲染菜单列表
        <a-menu-item v-if="item.children === false" :key="item.router"> // 顶级菜单
          <span>{{ item.name }}</span>
        </a-menu-item>
        <a-sub-menu v-else :key="item.router"> // 可以展开的二级菜单
          <span slot="title"><span>{{ item.name }}</span></span>
          <a-menu-item v-for="menuChildren in item.children" :key="menuChildren.router">{{ menuChildren.name }}</a-menu-item>
        </a-sub-menu>
      </template>
      </a-menu>

后端返回的JSON数据格式:

[
    {
        "name": "首页",
        "router": "/home/index",
        "children": false
    },
    {
        "name": "商品管理",
        "router": "/shop",  // 点击这个菜单不会跳转 只会展开 此处的router是为了设置key属性
        "children": [
            {
                "name": "商品分类",
                "router": "/home/shopClass"
            },
            {
                "name": "商品列表",
                "router": "/home/shopList"
            }
        ]
    },
    {
        "name": "个人设置",
        "router": "/user",
        "children": [
            {
                "name": "我的资料",
                "router": "/home/userEdit"
            },
            {
                "name": "登录记录",
                "router": "/home/userLoginRecord"
            }
        ]
    }
]
export default {
  data() {
    return {
      defaultSelectedKeys: [this.$route.path],
      openKeys: [''],
      menuList: [] // 此处为动态获取的菜单数组
    }
  },
  async created() {
    const result = await this.$http.post('home/menuList') // post后端服务器获取菜单数据
    this.menuList = result // 给data里面的菜单数组赋值数据
    this.handleData(result) // 处理数据
  },
  methods: {
  	// 处理数据展开应展开的菜单
    handleData(result) {
      function loop(list, keys = []) {
        // 循环【顶级菜单数组列表】 循环的数组下标用i表示
        // keys参数为当前菜单的所有上级菜单的router(用作openKeys的值)
        for (let item of list) {
          if (item.router === this.$route.path) {
          	// 如果路由path与item.router相等则直接返回当前路由的所有上级的router
            return [...keys]
		  } else if (item.children && item.children.length) {
		    // 如果item.router不等于当前$router.path则递归调用loop函数,传入item.children、[...keys, item.router]
		    let tempResult = loop(item.children, [...keys, item.router])
		    if (tempResult !== false) {
		      return tempResult
		    }
		  }
        }
        return false
      }
      this.openKeys = loop(result)
    },
    onOpenChange(openKeys) {  // 当菜单被展开时触发此处
      /* 
      经测试传入的变量openKeys是数组 点击已经展开的菜单时传入的是空数组
      点击未展开的菜单时传入的是[当前展开菜单的key,点击的菜单key]
      下面的if判断用openKeys === [] 无效 所以我只能判断数组length是否等于0
      */
      if (openKeys.length !== 0) {  
        this.openKeys = [openKeys[1]]
      } else {
        this.openKeys = ['']
      }
    },
    clickItem(obj) {
      this.$router.push(obj.key)
    }
  }
}