小程序页面滚动穿透
一、场景
- 在项目当中,基础遇到这样的需求
有一个长列表,或者其他可滚动展示的页面,
在这个页面会弹出一个Modal
层,如下:
贝壳找房的 的筛选栏
二、问题
如果这个弹框内容不可滚动,不会有太大问题;
但是当弹出内容是可以滚动的时候,就会有问题,
触摸没有滚动的区域会发现滚动可以穿透,会传递给下面的列表页面,
三、解决办法
程序员是面向Google编程的,找到了下面的解决办法:
- 监听弹框状态,如果弹框展示就给列表 添加对应样式
// isShowMask 弹框是否展示
<view class="dog-container {{isShowMask ? 'bottom-fixed' : ''}}"></view>
.bottom-fixed {
position: fixed;
left: 0;
top: 0;
overflow: hidden;
}
- 给遮罩层添加
catchtouchmove
的阻止
myCatchTouch: function () {
return;
}
<view wx:if="{{alert}}" catchtouchmove="myCatchTouch">
<template is="alert" data="{{alertData}}" />
</view>
这样的话,底部的列表内容就不会出现溢出,也自然不会滚动,
::: warning
但是,这样的做法有一个弊端,
不会去记录我之前访问的位置,也就是每次点开弹框,列表位置会归零,体验终归是不好的。
:::
四、升级方案
于是我去翻了一些开源小程序UI的Demo,去试试看这种弹框类型的交互,
最后发现在Taro UI
中有一个组件,Float LayOu
,是没有出现穿透的,列表位置也没有发生改变,
- 于是,我翻了源码,发现他是这样写的(有删减):
// 重点A:阻止事件冒泡
handleTouchMove = (e) => {
e.stopPropagation()
}
render() {
return (
<View className='rootClass' onTouchMove={this.handleTouchMove}>
<!-- 遮罩层 -->
<View onClick={this.close} className='at-float-layout__overlay' />
<View className='at-float-layout__container layout'>
<View className='layout-body'>
<!-- 重点B: ScrollView(开启scrollY)-->
<ScrollView
scrollY
scrollX={false}
className='layout-body__content'
>
{this.props.children}
</ScrollView>
</View>
</View>
</View>
)
}
- 思路解析:
i、首先,需要在自定义弹框的根元素,添加 onTouchMove
监听,并阻止时间的冒泡
<View className='rootClass' onTouchMove={this.handleTouchMove}>
ii、但是,里面的内容,就不能滚动了,那么,可以使用 ScrollView
代替View
,并开启Y轴的滚动
<ScrollView
scrollY
scrollX={false}
className='layout-body__content'
>
<!-- 内容区域-->
<!-- 内容区域-->
</ScrollView>
按照这样的思路,我在项目里面尝试了下,果然奏效,这样的方式更优雅体验也更好。
笔者使用了Taro,但原理都是一样的。
- 最终效果:
五、关于stopPropagation
简单来说:
::: tipJavaScript
中,冒泡和捕获是事件流的两种行为,使用event.stopPropagation()可以起到阻止捕获和冒泡阶段中当前事件的进一步传播。
而使用event.preventDefault()可以取消默认事件。
:::
事件流
事件流描述的是从页面中接受事件的顺序,分为
-
IE的事件流是 事件冒泡流,
-
标准的浏览器事件流是 事件捕获流。
好了,希望对大家有用,对事件流有兴趣的可以自行Google
或者看下这片文章:JavaScript的事件流
Ending…
来源:oschina
链接:https://my.oschina.net/u/4273344/blog/4327766