Cascader级联组件的实现细节与常见问题解决方案

雯雯的笔记 组件 阅读 1,055
赞 21 收藏
二维码
手机扫码查看
反馈

又踩坑了,Cascader级联滚动失效

前几天在做一个后台管理系统的时候,用了Element Plus的Cascader组件。本来觉得挺简单的功能,结果在手机端测试时发现了个大问题:下拉菜单里的滚动条完全没法用!用户只能看到前面几项,后面的内容根本滑不动。

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时遇到其他问题,或者有更好的解决方案,欢迎在评论区交流。最近还在研究它的性能优化方案,后续会继续分享这类实战经验。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论