一、场景

  • 在项目当中,基础遇到这样的需求

有一个长列表,或者其他可滚动展示的页面,
在这个页面会弹出一个Modal层,如下:

贝壳找房的 的筛选栏

小程序滑动穿透问题的解决 - 图1

二、问题

如果这个弹框内容不可滚动,不会有太大问题;

但是当弹出内容是可以滚动的时候,就会有问题,

触摸没有滚动的区域会发现滚动可以穿透,会传递给下面的列表页面,

三、解决方案

这里使用了Taro,但原理都是一样的。

思路解析

i、首先,需要在自定义弹框的根元素,添加 onTouchMove 监听,并阻止时间的冒泡

  1. // 重点A:阻止事件冒泡
  2. handleTouchMove = (e) => {
  3. e.stopPropagation()
  4. }
  5. <View className='rootClass' onTouchMove={this.handleTouchMove}>

ii、但是,里面的内容,就不能滚动了,那么,可以使用 ScrollView代替View,并开启Y轴的滚动

  1. <!-- 重点B: ScrollView(开启scrollY)-->
  2. <ScrollView
  3. scrollY
  4. scrollX={false}
  5. className='layout-body__content'
  6. >
  7. <!-- 内容区域-->
  8. <!-- 内容区域-->
  9. </ScrollView>

完整代码

  1. // 重点A:阻止事件冒泡
  2. handleTouchMove = (e) => {
  3. e.stopPropagation()
  4. }
  5. render() {
  6. return (
  7. <View className='rootClass' onTouchMove={this.handleTouchMove}>
  8. <!-- 遮罩层 -->
  9. <View onClick={this.close} />
  10. <!-- 重点B: ScrollView(开启scrollY)-->
  11. <ScrollView
  12. scrollY
  13. scrollX={false}
  14. className='layout-body__content'
  15. >
  16. <!-- 内容区域-->
  17. <!-- 内容区域-->
  18. {this.props.children}
  19. </ScrollView>
  20. </View>
  21. )
  22. }

最终效果

小程序滑动穿透问题的解决 - 图2

四、关于stopPropagation

JavaScript的事件流

简单来说:
JS中,冒泡和捕获是事件流的两种行为,
使用event.stopPropagation()可以起到阻止捕获和冒泡阶段中当前事件的进一步传播。
而使用event.preventDefault()可以取消默认事件。

事件流

事件流描述的是从页面中接受事件的顺序,分为

  • IE的事件流是 事件冒泡流,
  • 标准的浏览器事件流是 事件捕获流。