You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ever since the first release of Chrome for Android, this delay was removed if pinch-zoom was also disabled. However, pinch zoom is an important accessibility feature. As of Chrome 32 (back in 2014) this delay is gone for mobile-optimised sites, without removing pinch-zooming! Firefox and IE/Edge did the same shortly afterwards, and in March 2016 a similar fix landed in iOS 9.3.(from google developer)
If the preventDefault method is called on this event, it should prevent any default actions caused by any touch events associated with the same active touch point, including mouse events or scrolling.(W3C)
In user agents that support firing click and/or contextmenu, calling preventDefault during a pointer event typically does not have an effect on whether click and/or contextmenu are fired or not.(W3C)
React iScroll Fastclick的事件机制讲解
移动h5应用两个很影响用户体验的问题:
-webkit-overflow-scrolling : touch;
可以部分解决1. 2.问题,但很不完美,至少有两个问题:iScroll
或者类似模拟滚动的方案,是当前的最优选择.问题3的300-350ms延迟是因为浏览器会等待来判断是否是双击.据说大部分现代浏览器已经没有这个问题.然而我们实际测试中,这个问题依然在很多设备中存在,包括IOS9以上的设备!
React也基于此否决官方实现一个无延迟的tap: facebook/react#436 (comment)
并推荐用插件react-tap-event-plugin来暂时解决这个问题.
但这里有一个引入插件和将
onClick
事件改成onTouchTap
事件的成本(而且说不定以后确实不存在这个问题,又要改回onClick
)react-tap-event-plugin:
这个成本是我更愿意使用
react-fastclick
的原因.但是并没有完事大吉,如果不当的使用可能会出现:
为了彻底搞明白这里面的猫腻,解决恼人bug,我们去看看他们内部到底是如何实现的.
Q1
react-fastclick
为什么fast?react-fastclick
重写了React.createElement
以禁止执行组件的onClick
回调,并添加onTouchStart
,onTouchMove
,onTouchEnd
来监听模拟click事件,并在onTouchEnd
中触发click回调.由于touch事件不存在delay的问题,因此就解决这个问题.
Q2 React的事件处理机制是怎样的,使用事件代理了吗?
React采用的是顶层(document)的事件代理机制,并实现了一个
synthetic event
,解决 IE 与W3C 标准实现之间的兼容问题。并且React代理在顶层的事件监听也支持stopPropagation,也是因为React的synthetic event
的内部实现.所有通过 JSX 这种方式绑定的事件都是
synthetic event
。 在组件创建时react会把事件监听存储在一个map中,并且在组件卸载(unmount)的时候自动销毁绑定的事件。Q3
iScroll
为什么会使React
onClick
无效?iScroll会监听元素的touch事件,并在touchstart的回调中执行:
e.preventDefault();
也就是禁止了
touchstart
的默认行为,这会产生一个副作用:同时会阻止click
事件的触发.好,我们知道了,元素的click事件由于
iScroll
的touchstart
preventDafault()
导致无法触发,也就无法冒泡到document
上触发react
的onClick
回调.Q4
iScroll
为什么在某些浏览器下click
却正常?Q3回答了
iScroll
导致click
无效,奇怪的是在有些浏览器下,click
是能正常触发的.这个原因要落在另一个事件
pointer
上.某些浏览器支持pointer
事件,这时iScroll会去监听pointer
事件而不是touch
事件,然而pointer
事件的preventDefault()
并不会阻止click
事件的触发.这是iScroll一个坑.
我们很容易想到让iScroll不监听
pointer
从而使各浏览器表现一致,这样设置:然而这里有另一个坑,在支持
pointer
事件的浏览器里,iscroll无法滚动了!Q5 为什么在支持
pointer
事件的浏览器里,iscroll无法滚动了?按理我们设置
disablePointer
了,iScroll
应该用touch
事件去处理啊.这个锅仍然是iScroll的,iScroll判断当浏览器支持
pointer
事件时,会禁用touch
.即使我们设置了disablePointer : true
也一样.具体情况是
disableMouse
,disablePointer
,disableTouch
的默认值并不是false
,而是动态去设置的:这是一种
fallback
的机制,当utils.hasPointer
为true
,即浏览器支持pointer
事件时,disableTouch
会被默认设为true
!然而在iScroll文档中没有任何说明.这也是一个bug,正确的判断方式应该为
disableTouch : (utils.hasPointer && !options.disablePointer) || !utils.hasTouch
在这个bug修复之前,我们需要这样设置:
Q6 怎么解决
iScroll
的点击无效?网上答案和iScroll官方给的答案是在iScroll初始化时加参数:
click : true
或tap : true
这实际上是iScroll触发了一个自定义的click事件
这是有效的.但是如果是和
fastclick
配合,实际上不需这个设置.Q7 使用
fastclick
不加click : true
也能点击?没错,正如Q1和Q3所说,
fastclick
实际上监听的是touch
事件,而iScroll
影响的是click
事件,所以使用fastclick
是可以正常点击的.Q8 使用了
onClick : true
为什么会造成重复点击?实际是和Q4是同一问题,在那些支持
pointer
事件的浏览器中,会浏览器触发一次,iScroll
模拟事件触发一次.至此,我们已经彻底弄清楚了
React
iScroll
Fastclick
的事件机制,安心的去使用这些技术吧!The text was updated successfully, but these errors were encountered: