Banner 图来自 ant.design

在封装按钮组件时候,我们一般喜欢通过 :active 实现按钮的点击态。然而有个容易被忽略的细节是:在移动设备中按下然后在该元素上移动一定的距离后点击态会消失

如果你这个组件是专门为移动端设计的,你还可能会使用各种 touch 事件的组合来模拟按钮的点击。这时候就会带来一个问题,基于上一段的设定,很可能当用户松开手指之前按钮的点击态已经消失了,点击态消失给用户的暗示就是不会触发点击事件了。

可是基于 touch 事件模拟的点击是开发者行为,而移动设备上按钮 :active 状态的变化是浏览器行为,这二者很难保持一致(后文会提到间接监听到按钮 :active 状态变化的办法)。因此该用户在松开手指的时候大概率还是会触发事件,这是一个不太符合预期的行为:

解决办法是可以基于 Mouse 事件来搞,比如 mouseup 和 click,这两个事件和 :active 行为是一致的。如果担心不用 touch 会带来触摸延时问题,可以尝试其他移动设备点击延迟的解决方案。经测试,解决了延迟问题后,移动端的 click 和 mouseup 事件是等效的,可以概括为:在某元素上按下,未发生过一定的移动且未移开过该元素,那么松开的时候会触发。

不过如果你想实现除了点击之外更多的触摸事件比如长按,那 Mouse 事件就很难搞定了,因为在移动端对元素进行长按会触发 mousemove 从而导致其他 Mouse 事件不再触发。这时候有个更好的选择是使用 Pointer 事件,它几乎可以完美替代 Touch 和 Mouse 事件。另外,前文中说的 :active 状态的丢失实际上可以使用如下 Pointer 事件来间接监听:

  • pointerleave(不支持冒泡)
  • pointerout
  • pointercancel

不过要注意:多点触控也会导致 :active 状态丢失,以上事件并不能覆盖该种情况。

ps:录制 Gif 图的过程很痛苦…chrome 移动端调试时候长按时候一不小心会呼出菜单或选中文字,呼出菜单的问题可以通过 JS:window.oncontextmenu = () => false 来解决;选中可以通过 CSS:user-select: none 来解决。


 评论