您和用户都希望移动网站应用能够在触摸时做出流畅的响应和滚动。开发它们应该很容易,但遗憾的是,移动 Web 浏览器在滚动期间如何响应触摸事件,在 TouchEvent 规范中被留作实现细节。因此,方法大致可分为 4 类。这种情况揭示了在实现流畅滚动和保持开发者控制之间存在根本性矛盾。
四种不同的触摸事件处理模型?
浏览器之间的行为差异可分为四种模型。
正常的同步事件处理
系统会在滚动期间发送 Touchmove 事件,并且每次滚动更新都会阻塞,直到 Touchmove 处理完成。这是一种最简单、最强大的滚动方式,但对滚动性能不利,因为这意味着滚动期间的每个帧都必须在主线程中阻塞。
浏览器:Android 浏览器(Android 4.0.4、4.3)、移动 Safari(滚动 div 时)
异步处理 touchmove 事件
系统会在滚动期间发送 touchmove 事件,但滚动可以异步进行(在滚动开始后,系统会忽略 touchmove 事件)。这可能会导致事件“重复处理”,例如,在网站对 touchmove 执行操作并对该事件调用 preventDefault(告知浏览器不要处理该事件)后,继续滚动。
浏览器:移动 Safari(滚动文档时)、Firefox
滚动时抑制了 Touchmove
滚动开始后,系统不会发送 Touchmove 事件,并且在 Touchend 事件之后才会恢复。在这种模型中,很难区分静止触摸和滚动操作。
浏览器:三星浏览器(发送了 mousemove 事件)
滚动开始时触摸取消
您无法同时实现滚动流畅度和开发者控制,而此模型清楚地说明了流畅滚动和事件处理之间的权衡,类似于 Pointer Events 规范的语义。某些可能需要跟踪手指的体验(例如下拉刷新)无法实现。
浏览器:Chrome 桌面版 M32 及更高版本、Chrome Android 版
变更原因
Android 版 Chrome 目前使用的是 Chrome 的旧版模式:在滚动开始时触发 touchcancel,这可以提升滚动性能,但会导致开发者感到困惑。具体而言,有些开发者不知道 touchcancel 事件或如何处理它,这导致某些网站无法正常运行。更重要的是,整类界面滚动效果和行为(例如拉动以刷新、隐藏条和贴靠点)很难或根本无法正确实现。
与添加专门的硬编码功能来支持这些效果不同,Chrome 旨在专注于添加平台基元,以便开发者直接实现这些效果。如需对此理念进行一般性阐述,请参阅 A Rational Web Platform。
Chrome 的新模型:节流异步 Touchmove 模型
Chrome 将引入一种新行为,旨在提高滚动时与为其他浏览器编写的代码的兼容性,并支持在滚动时依赖于获取 touchmove 事件的其他场景。此功能默认处于启用状态,您可以使用以下标志 chrome://flags\#touch-scrolling-mode
将其关闭。
新行为如下:
- 第一个 touchmove 会同步发送,以允许取消滚动
- 在主动滚动期间
- touchmove 事件会异步发送
- 节流为每 200 毫秒 1 个事件,或者超出 CSS 15 像素 slop 区域
- Event.cancelable 为 false
- 否则,当主动滚动终止或因达到滚动限制而无法滚动时,touchmove 事件会照常同步触发
- 当用户抬起手指时,系统始终会触发 touchend 事件
您可以在 Chrome(Android 版)中试用此演示,并切换 chrome://flags\#touch-scrolling-mode
标志以查看差异。
请与我们分享您的想法
异步 Touchmove 模型有望提高跨浏览器兼容性,并实现新类的触摸手势效果。我们很想听听开发者的想法,并了解您可以使用它做出哪些富有创意的事情。