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

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


功能界面

主要问题

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

滚动右侧整个页面跟着滚动

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

<div className="nonius"
  id="nonius"
  onTouchStart={this.sidebarTouchStart.bind(this)}
  onTouchMove={this.sidebarTouchMove.bind(this)}
  onTouchEnd={this.sidebarTouchEnd.bind(this)}
>

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

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

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


chorme 开发工具警告提示

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

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/web/updates/2017/01/scrolling-intervention

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

根据 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/zh-CN/docs/Web/CSS/touch-action

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


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对passive属性支持的相关语法

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

原文地址: http://w3cay.com/post/dc49b55.html?title=React-scroll&from=jianshu

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,470评论 1 11
  • 我们知道滚动响应是至关重要的在用户移动端网站上触摸的时候,然而触摸事件监听器经常会导致严重的滚动性能问题。Chro...
    loushumei阅读 2,092评论 0 4
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,386评论 1 45
  • 光匆匆流逝,记忆永远不老,每每翻开这些照片,与你们一同度过的欢乐时光仿佛还在昨天,时光无情,记忆永存,欢乐的时光永...
    A颜妍阅读 211评论 0 0
  • 创业是一个苦逼的事情,不是每个人都可以创业,不是创业的人都会成功,很多的细节决定了你是否真正的创业,是否能够成功。...
    管理老马阅读 186评论 1 1