Cascader级联组件的实现细节与常见问题解决方案
又踩坑了,Cascader级联滚动失效
前几天在做一个后台管理系统的时候,用了Element Plus的Cascader组件。本来觉得挺简单的功能,结果在手机端测试时发现了个大问题:下拉菜单里的滚动条完全没法用!用户只能看到前面几项,后面的内容根本滑不动。
这里我踩了个坑,折腾了半天才发现是touch事件被阻止了。其实PC端是正常的,鼠标滚轮可以正常使用,但在移动端touchmove就完全没反应。这个问题直接影响到用户体验,必须得解决。
排查过程:从CSS到JS的全面尝试
一开始我以为是CSS样式的问题,检查了overflow属性,确认容器确实设置了overflow-y: auto。然后又试了各种css hack,比如加个-webkit-overflow-scrolling: touch,但都没效果。
后来怀疑是z-index层级问题,把cascader的z-index调到9999还是不行。接着又试了给body加overscroll-behavior: contain,依然没用。
折腾了半天发现,其实是组件库默认阻止了touch事件。这时候才想起来去看Element Plus的官方文档,果然有相关说明,但写得很简略。
三种方案对比,我选了最简单的
研究了一圈,总结出三个可行的解决方案:
- 1. 自己重写一个Cascader组件
- 2. 使用popupProps配置
- 3. 手动监听并恢复touch事件
第一个方案工作量太大,pass。第三个方案需要操作DOM,感觉不够优雅。最后选择了第二种方式,通过popupProps配置来解决问题。
核心代码就这几行
说到底,解决方案就是正确配置Cascader的props参数。下面是完整的代码实现:
<template>
<el-cascader
v-model="selectedValue"
:options="options"
:props="cascaderProps"
placeholder="请选择分类"
/>
</template>
<script setup>
import { ref } from 'vue'
const selectedValue = ref([])
const options = ref([
{
value: 'category1',
label: '分类一',
children: [
{ value: 'sub1', label: '子分类1' },
{ value: 'sub2', label: '子分类2' }
// 这里省略更多选项...
]
},
// 更多顶级分类...
])
const cascaderProps = {
popupProps: {
onTouchstart: (e) => {
e.stopPropagation()
},
onTouchmove: (e) => {
e.stopPropagation()
}
},
expandTrigger: 'hover'
}
</script>
<style scoped>
/* 样式可以根据项目需求自行调整 */
</style>
这里要特别注意popupProps的用法,很多同学容易忽略这个配置项。通过stopPropagation来阻止事件冒泡,就能让内部的滚动正常工作了。
还有两个小问题需要注意
虽然主要问题解决了,但改完后发现还有两个小问题:
1. 在某些低端安卓机上,快速滑动时偶尔会出现卡顿。这个问题暂时还没找到完美解决方案,不过影响不大,大部分设备都正常。
2. 当选项过多时,渲染性能会有点问题。后来加了个懒加载的配置,分批加载数据,基本解决了:
const cascaderProps = {
lazy: true,
lazyLoad(node, resolve) {
const { level } = node
setTimeout(() => {
// 模拟异步获取数据
const nodes = fetch(https://jztheme.com/api/cascader?level=${level})
.then(res => res.json())
.then(data => resolve(data))
}, 500)
},
// 其他配置...
}
技术细节补充:为什么会出现这个问题
深入研究了一下,这个问题的本质其实是事件委托和默认行为的冲突。大多数UI组件库为了防止误触,都会在弹出层上阻止touch事件的默认行为。这样做确实能避免一些意外情况,但也带来了滚动失效的问题。
另外还发现一个有意思的现象:不同版本的Element Plus对touch事件的处理方式不太一样。我在升级到最新版后,发现官方已经优化了这部分逻辑,默认情况下滚动已经可以工作了。不过保险起见,还是建议保留popupProps的配置。
以上是我踩坑后的总结
这次Cascader的坑算是填上了,不过也提醒我们几个重要的开发经验:
- 1. 第三方组件库的默认行为可能跟预期不一样,一定要仔细看文档
- 2. 移动端的兼容性问题往往比想象中复杂
- 3. 遇到问题先别急着改代码,理清楚原理再动手
如果你在使用Cascader时遇到其他问题,或者有更好的解决方案,欢迎在评论区交流。最近还在研究它的性能优化方案,后续会继续分享这类实战经验。

暂无评论