首页 前端知识 【Vue3】el-menu的踩坑和使用

【Vue3】el-menu的踩坑和使用

2024-09-01 23:09:04 前端知识 前端哥 1336 671 我要收藏

el-menu在作为导航时非常好用,有非常多的使用场景,但是这个组件本身有一些问题,在使用时需要额外注意:

一、el-menu多次修改default-active时,视图不更新Bug:

解决办法很简单:

// 不高亮任何地方 如果写成固定值,则第二次执行该语句时el-menu不会更新视图
curNavActive.value = Math.random().toString()
// 高亮指定index的el-menu-item 如果不这样写,则第二次执行该语句时el-menu不会更新视图 
curNavActive.value = ''
nextTick(() => {
   curNavActive.value = '知识库'
})
复制

二、el-menu-item点击事件会冒泡到el-sub-menu的Bug:

el-menu同时给`el-sub-menu`和下面的`el-menu-item`绑定事件时,点击el-menu-item,事件会冒泡到el-sub-menu中,而且el-menu-item的click事件在组件内部做了处理,不会返回event事件的参数,所以无法使用事件修饰符直接阻止冒泡事件,只能在el-sub-menu的事件中判断:

const subMenu_clickEvent = ($event: MouseEvent) => {
  // el-menu-item事件会冒泡到这里 如果点击的文件夹下面的item 不要执行任何操作
  let subMenuTitle = document.querySelector('.subMenuTitle')
  if ($event.target !== subMenuTitle) {
    return
  } else
    // 真实el-sub-menu应该执行的事件 ...
  }
}
复制

三、el-menu阻止el-sub-menu的展开和折叠事件:

不要把事件挂载在 el-sub-menu本身上,而是要挂载在其 title插槽中,并且阻止其事件冒泡即可!

<el-sub-menu
   index="知识库"
>
   <template #title>
<!-- 在 title插槽中绑定一个事件 并阻止其冒泡,这样在点击这个区域时,
el-sub-menu就不会展开/折叠了 -->
       <el-icon><Collection /></el-icon>
       <div class="subMenuTitle" @click.stop="switchToLibHome">
        中医知识库
       </div>
   </template>
   <el-menu-item
       v-for="item in $knStore.curSourceList"
       :key="item.id"
       :index="item.id + '知识源'"
       @click="switchViewFile(item)"
   >
    <span>{{ item.name }}</span>
   </el-menu-item>
</el-sub-menu>
复制

在 title插槽中,使用一个足够大的div来包裹里面的内容(注意不要包裹icon图标),这样用户只能通过点击这个 div 之外的部分来展开和折叠 sub-menu。

就相当于阻止了sub-menu自带的展开/折叠事件。

设置 width: 100% 和 flex-grow:1 都行,但是建议设置为width: 100% ,而且不要懒省劲用style设置行内样式,因为这个地方比较特殊,它的样式优先级比较低才好。

不把事件挂载到el-sub-menu本身还有一个好处,现在子菜单下面的子节点的事件不会再冒泡到el-sub-menu上了。也就无需判断 event.target了。

但是这样一来,el-menu就不能进行收起折叠了,因为这个div有宽度相关的样式,所以就会出现el-sub-menu没有正常折叠的bug:

如果el-menu不需要收起,那么到这里就算结束了,展开情况下菜单使用很正常,但是如果还想对收起状态进行处理,那就需要在el-menu菜单收起时,控制其标签样式了:

1、首先,将div更换为span标签(这很重要!),并设置css样式为 width: 100% 。

<el-sub-menu
index="知识库"
expand-close-icon="CaretBottom"
expand-open-icon="CaretTop"
>
<template #title>
<!-- icon图标一定一定要写在span外面,否则el-menu收起时会没有图标! -->
<el-icon><Collection /></el-icon>
<!-- div标签也一定要改为span标签! -->
<span class="subMenuTitle" @click.stop="switchToLibHome">
中医知识库
</span>
<!--
<div class="subMenuTitle" @click.stop="switchToLibHome">
中医知识库
</div>
-->
</template>
......
</el-sub-menu>
复制

2、然后在el-menu整体收起时,用js获取这个标签,并将这个标签的width设置为0即可。

但是在研究后发现,其实elementUI内部在el-menu收起时已经将内部所有span标签的宽度设置为0了,只不过优先级没有我们设置的优先级高,所以没有生效

也就是说,我们只需要降低span标签的 width:100% css样式的优先级即可,我是通过移动css代码的位置来降低其优先级的,反正只要优先级比elementUI的低就可以:

这样就不需要js去控制css样式了,更简单方便。

最后给这个span标签加上超长省略样式:

// el-menu子菜单样式(不要移动它的位置,要保持其css的低优先级,否则el-menu收起时会出现占位问题)
.subMenuTitle {
width: 100%;
// 超长文本截断
overflow: hidden;
text-overflow: ellipsis;
}
复制

现在好像一切都可以了,但是我们还需要做最后一步:

给 sub-menu的小图标也注册个点击事件,防止在el-menu收起时,点击图标无效的情况发生。

<template #title>
<!-- 给小图标也注册点击事件,不然收起时点不到下面的span标签 -->
<el-icon @click.stop="switchToLibHome"><Collection /></el-icon>
<span class="subMenuTitle" @click.stop="switchToLibHome">
{{ $knStore.curLib?.name }}
</span>
</template>
复制

最后的效果很完美:

四、el-sub-menu子项过多,折叠时无法完全显示Bug:

可以看到,在收起状态下,el-sub-menu的弹窗即使上下两端都顶到了头,也没显示完全,下面还有1个元素。

而这个el-sub-menu的弹窗默认是在body中插入的,我在Vue子页面中不能只通过css去操控body中的元素。

所以就需要使用js来操控其样式了。

1、先给popper弹窗加上一个自定义样式:

<el-sub-menu
index="..."
popper-class="subMenuPopper_knowledgeLib"
>
...
</el-sub-menu>
复制

2、再在折叠el-menu之后使用js去操控submenu的弹窗样式

// 收起el-menu
const foldNav = () => {
isCollapse.value = true
navWidth.value = 5.5
// 折叠后 给知识源列表弹窗添加样式 避免知识源文件过多时弹窗无法完全显示所有文件列表
setTimeout(() => {
let subMenuPopper: HTMLElement | null = document.body.querySelector(
'.subMenuPopper_knowledgeLib'
)
if (subMenuPopper) {
subMenuPopper.style.maxHeight = '80vh'
subMenuPopper.style.overflow = 'auto'
}
}, 2000)
}
复制

这里不知道为什么使用 nextTick 始终获取不到这个popper元素,可能是这个元素的渲染比较特殊吧,只能是使用定时器来获取,1秒还是2秒都可以。

更改样式之后的效果:

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17471.html
标签
评论
发布的文章

安装Nodejs后,npm无法使用

2024-11-30 11:11:38

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!