资讯专栏INFORMATION COLUMN

React禁止页面滚动踩坑实践与方案梳理

zhjx922 / 1537人阅读

摘要:最近在使用技术栈重构一个单页应用,其中有个页面是实现城市选择功能,主要是根据城市的首字母来快速跳转到相应位置,比较类似原生中的电话联系人查找功能,页面如图主要问题在上下滑动右侧定位的元素时,页面会跟着一起滑动当然这个现象在开发过程中应该会经

最近在使用 React 技术栈重构一个单页应用,其中有个页面是实现城市选择功能,主要是根据城市的首字母来快速跳转到相应位置,比较类似原生 APP 中的电话联系人查找功能,页面如图

主要问题

在上下滑动右侧 fixed 定位的元素时,页面会跟着一起滑动

当然这个现象在开发过程中应该会经常遇到,比如弹起 modal 框时,如果 modal框的内容高度小于框高度,滑动内容也会导致页面跟着滑动, 那么在 React 中像往常一样处理

使用 React 提供的事件绑定机制,分别绑定三个 handler ,在 onTouchMove 事件中,我希望通过 preventDefault 能够阻止父级元素的滚动

sidebarTouchMove(e) {
  e.preventDefault();
  ...
}

但实际的反馈却事与愿违,在调试中,我发现 Chrome 是有警告的,并且没有达到想要的效果

根据警告提示,找到的原因是

AddEventListenerOptions defaults passive to false. With this change touchstart and touchmove listeners added to the document will default to passive:true (so that calls to preventDefault will be ignored)..
If the value is explicitly provided in the AddEventListenerOptions it will continue having the value specified by the page.
This is behind a flag starting in Chrome 54, and enabled by default in Chrome 56. See https://developers.google.com...

来源: https://www.chromestatus.com/...

根据 chrome 的提示得知,是因为 Chrome 现在默认把通过在 document 上绑定的事件监听器 passive 属性(后面细说)默认置为 true,这样就会导致我设置的 e.preventDefault() 被忽视了。当然 Chrome 的这个做法是有道理,是为了提高页面滚动的性能,那么为了防止带来的副作用,官方考虑的很周到,给我们提供了一个 CSS 属性专门用来解决这个问题

#fixed-div {
  touch-action: none;
}
In rare cases this change can result in unintended scrolling. This is usually easily addressed by applying a touch-action: nonestyle to the element where scrolling shouldn"t occur.

https://developer.mozilla.org...

加上了这个属性,感觉世界总算和平了,But!在 ios 系统上测试发现,这个属性 x 用没有,查了下 Can I Use

确定无误,就是不支持,所以这个属性只在 Chrome 安卓等机型下是支持的,ios 这个就用不了,理想很丰满,显示很骨感。既然不兼容,那只能降级处理了,为了保证良好的功能体验,感觉是还要从 passive 上做处理,说到 passive 根据 MDN文档:addEventListener 的介绍,为了提高页面滚动性能,大多浏览器都默认把 touchstart 和 touchmove 在文档元素上直接注册的这个事件监听器属性设置成 passive:true ,而通过 AddEventListener 注册的事件依然没有变化

既然现在默认将事件 passive 的属性默认设置为 true ,那我就显式设置为 false 好了,查遍 React 的文档,也没发现事件监听器可以支持配置这个属性的,在 github 上发现这个帖子 Support Passive Event Listeners #6436 目前看依然是 open 状态的,现在不确定有没有支持这个属性

解决方案

既然这样,只能多带带对 touchmove 通过 AddEventListener 方法去注册事件监听了

// 为元素添加事件监听   
document.getElementById("nonius").addEventListener("touchmove", (e) => {
  // 执行滚动回调
  this.sidebarTouchMove(e)
}, {
  passive: false //  禁止 passive 效果
})

加上这个方法后,this.sidebarTouchMove(e) 方法中的 e.preventDefault() 方法就可以正常使用了,而且没有警告提示,问题到此就算解决了

总结

总结下,这里的坑主要是 chrome 和 safari 平台的标准不统一导致的,新的标准出台,其它宿主环境不能很好的支持,当然 react 官方对这个属性的支持也比较慢,同样的前端 UI 框架 Vue 就处理的很棒

不小心暴露了,我是个 Vue粉,233
ok,完 ~

巴拉巴拉传送门 -> 原文链接

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95906.html

相关文章

  • React 历史项目维护优化实践

    摘要:本文介绍了作者接手维护一个中型历史项目时的一系列改进实践,包括模块结构拆分业务逻辑梳理打包优化等。代码中如菜单名称结构表单字段名等的各种硬编码配置分散在各处。最后,在提升面向开发者的打包体验方面,本次优化中主要实现的是与的解耦。 本文介绍了作者接手维护一个中型 React 历史项目时的一系列改进实践,包括模块结构拆分、业务逻辑梳理、Webpack 打包优化等。 背景 这是一个 PC 的...

    toddmark 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    khs1994 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<