最近用react作了一个H5端的页面,主要实现了一个弹层滑动选择的功能,效果如图:
遇到了一个问题,当在底部弹出层进行滚动选择城市区划时,蒙版后的页面也会随着滚动。css
这种现象在开发过程当中常常会遇到,常规思路就是使用event.preventDefault
阻止父级元素的滚动:react
<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>
滚动事件代码片断git
handleTouchMove = (event) => { event.preventDefault(); ... };
但这波操做事后,却未能如愿以偿,在调试的时候Chrome的告警,如冷冷的冰雨打在个人脸上:
根据告警关键字用Google百度了一番,等到了以下结论:github
因为浏览器必需要在执行事件处理函数以后,才能知道有没有调用preventDefault()
,这就致使了浏览器不能及时响应滚动,略有延迟。因此为了让页面滚动的效果如丝般顺滑,从 chrome56 开始,在 window、document 和 body 上注册的
touchstart
和touchmove
事件处理函数,会默认为设置passive: true
。浏览器忽略 preventDefault() 就能够第一时间滚动了。chrome
细细揣测一番,其实官方的考虑仍是有道理的,也是周到的。在CSS中提供了一个属性touch-action
,用于指定某个给定的区域是否容许用户操做,以及如何响应用户操做。
据此,个人解决方案就是设置这个CSS属性:浏览器
touch-action: none;
感受总算万事大吉利了,那个手机试一把,用iPhone的Safari浏览器代开后,依然并无什么卵用。是的,九成是浏览器兼容问题,查看CanIUse,果不其然。
那么既然如此,剩下的解决方案,就只有在绑定事件的时候显式的设置{ passive: false }
,查了一圈React文档也没发现,能够支持配置这个属性的方法。此处真心感叹一句不如Vue方便,若是是Vue就能够这么写:函数
<div v-on:touchmove.prevent="handleTouchMove"></div>
既然如此,就只能用原生的事件绑定了this
document.getElementById("picker").addEventListener('touchmove', this.handleTouchMove, { passive: false });
终于,世界和平了。spa