我们这边没有专门的产品经理,UI对产品的设计基本具有决定权,说实话,是有那么一点可怖的。

vue、vue-router、element-ui

需求:

导航菜单(el-menu)竖向展示的

  1. 鼠标移入一级菜单展示下面的子菜单,移出则收起来(手风琴模式,正常状态下只保持一个菜单展开出于展开状态,手动鼠标悬浮展开的不算)
  2. 选中某个子菜单时高亮对应的一级菜单,并且当鼠标移出高亮的这个菜单模块时不折叠,但是可以点击一级菜单进行折叠(注意:跟第一条有区别)

    问题

  3. element-ui的导航组件子菜单打开的触发方式可以通过 menu-trigger 参数控制,但是,只在菜单是水平展示(horizontal)的情况下生效。嘶~!我直想垂直模式滑动展开真的会有系统这么做吗?(只能自己修改了)

  4. unique-opened 参数可以控制是否只保持一个子菜单展开,但是在没有子菜单的情况下失效(需要手动修改)

    思路分析

    导航菜单使用递归组件

  5. 鼠标滑动展开关闭需求:

  • el-submenu 组件编写鼠标移入移出事件(mouseenter、mouseleave),拿到indexPath,调用open和close方法打开或者折叠菜单(注意:没有子菜单的一级菜单鼠标移入移出不做处理)
  1. 只保持一个菜单出于展开状态
  • 先配置 unique-opened 参数为 false ,以保证 openedMenus 只有一个( openedMenus 是el-menu内部维护的属性)

    一开始我想在子菜单展开折叠的回调事件(open、close)里写逻辑判断,但是不知道什么原因回调事件不触发(注意:open方法和open事件不一样,组件三大要素:属性、事件、方法),所以我就考虑在select回调事件里写逻辑了

  • 在菜单激活的select回调事件中,让上一个打开的菜单调用close方法关闭。(这里需要记录上次打开菜单的index,这里我使用sessionStorage记录)

代码展示

只展示代码片段,仅供参考
sessionStorage使用自己封装的,之前文章有写过,可以看一下

  1. menuEnter() {
  2. // isNest 是否还有子菜单 true:没有子菜单 false:有子菜单
  3. if (!this.isNest && this.item.alwaysShow) {
  4. this.$emit('handleOpen', this.basePath) // basePath: 一级菜单
  5. }
  6. }
  7. menuLeave() {
  8. // 存在子菜单,并且不是打开状态的菜单,鼠标离开的时候需要合起来
  9. if (!this.isNest && !this.curMenuIsOpened) {
  10. this.$emit('handleClose', this.basePath) // basePath: 一级菜单
  11. }
  12. }
  1. // 登录系统的时候,记录展开的菜单信息,在 mounted 里面获取 openedMenus ,并记录信息
  2. mounted() {
  3. // 获取当前展开的菜单 - array
  4. // 手风琴模式,只有一个展开菜单
  5. const {openedMenus = []} = this.$refs.menuRef // openedMenus 是内部属性
  6. if (openedMenus && openedMenus.length > 0) {
  7. // 获取展开菜单的 index
  8. const index = openedMenus[0];
  9. sessionStorage.put('preActiveMenu', index)
  10. }
  11. }
  12. methods: {
  13. handleOpen(indexPath) {
  14. this.$refs.menuRef.open(indexPath) // 调用 open 方法, 打开close,
  15. }
  16. handleClose(indexPath) {
  17. this.$refs.menuRef.close(indexPath) // 调用 close 方法, 关闭close
  18. }
  19. handlerSelect(index, indexPath) {
  20. // 1. 获取上次激活的菜单信息
  21. const _preActiveMenu = sessionStorage.get('preActiveMenu') || '';
  22. if (_preActiveMenu) {
  23. // 如果存在,则关闭该菜单,再打开新的
  24. this.$refs.menuRef.close(_preActiveMenu);
  25. }
  26. // 2. 记录这次激活的菜单信息
  27. if (indexPath.length > 0) {
  28. sessionStorage.put('preActiveMenu', indexPath[0])
  29. }
  30. }
  31. }

最终效果展示

1662116465481.png