乐趣区

React中禁止页面滚动

最近用 react 做了一个 H5 端的页面,主要实现了一个弹层滑动选择的功能,效果如图:遇到了一个问题,当在底部弹出层进行滚动选择城市区划时,蒙版后的页面也会随着滚动。
这种现象在开发过程中经常会遇到,常规思路就是使用 event.preventDefault 阻止父级元素的滚动:
<div className=”picker-column”>
<div
className=”picker-scroller”
style={style}
onTouchStart={this.handleTouchStart}
onTouchMove={this.handleTouchMove}
onTouchEnd={this.handleTouchEnd}
onTouchCancel={this.handleTouchCancel}
>
{this.renderItems()}
</div>
</div>
滚动事件代码片段
handleTouchMove = (event) => {
event.preventDefault();

};
但这波操作过后,却未能如愿以偿,在调试的时候 Chrome 的告警,如冷冷的冰雨打在我的脸上:根据告警关键字用 Google 百度了一番,等到了如下结论:
由于浏览器必须要在执行事件处理函数之后,才能知道有没有调用 preventDefault(),这就导致了浏览器不能及时响应滚动,略有延迟。所以为了让页面滚动的效果如丝般顺滑,从 chrome56 开始,在 window、document 和 body 上注册的 touchstart 和 touchmove 事件处理函数,会默认为设置 passive: true。浏览器忽略 preventDefault() 就可以第一时间滚动了。

细细揣测一番,其实官方的考虑还是有道理的,也是周到的。在 CSS 中提供了一个属性 touch-action,用于指定某个给定的区域是否允许用户操作,以及如何响应用户操作。据此,我的解决方案就是设置这个 CSS 属性:
touch-action: none;
感觉总算万事大吉利了,那个手机试一把,用 iPhone 的 Safari 浏览器代开后,依然并没有什么卵用。是的,九成是浏览器兼容问题,查看 CanIUse,果不其然。那么既然如此,剩下的解决方案,就只有在绑定事件的时候显式的设置 {passive: false},查了一圈 React 文档也没发现,可以支持配置这个属性的方法。此处真心感叹一句不如 Vue 方便,如果是 Vue 就可以这么写:
<div v-on:touchmove.prevent=”handleTouchMove”></div>
既然如此,就只能用原生的事件绑定了
document.getElementById(“picker”).addEventListener(‘touchmove’, this.handleTouchMove, { passive: false});
终于,世界和平了。

退出移动版