在台式机和移动设备上检测点击(或触摸)的最可靠方法是什么?

时间:2019-01-24 01:08:16

标签: javascript google-chrome

我正在订阅click元素上的button事件。如果您点击按钮,这似乎在移动设备上起作用,但是如果将其按住一会儿然后释放它,则不会触发。至少这就是我最近使用Chrome的Android手机上的运行方式。

所以我想在释放按钮时触发一些操作。因此,我假设我不应该去touchstart,因为它会在第一次按下按钮时触发。

  • 我需要订阅多个活动吗?哪个?
  • 如果我订阅了多个活动,是否需要preventDefault()

我找到了这篇文章,但来自2013年:https://www.html5rocks.com/en/mobile/touchandmouse/

3 个答案:

答案 0 :(得分:2)

经过一些尝试,似乎所有浏览器在这里的行为都不相同...

在Firefox和Android上的Chrome浏览器中,单击事件都被 contextmenu 事件丢弃,我还无法在Safari上进行测试。但是,在Firefox中,唯一会触发的事件是touchend,而在Chrome上,有时会触发 touchcancel (显然是在选择按钮中的文本时)。

因此,您需要监听 touchend 事件,该事件与 mouseup 事件不同,如果您确实将光标移到元素外部后也会触发开始单击,但如果您先在外部单击并随后将光标移到该元素上,则不会触发,对于 touchcancel 事件,该事件可能会在用户释放该位置之前触发一点(但这是我们可以获得的最新活动...)。

现在,要避免同时触发 click touchend / touchcancel 事件,您需要对事件处理程序进行反跳操作(即,强制事件处理程序在给定的时间间隔内仅运行一次),并且可能还防止 contextmenu 事件的默认行为。

// simple logs:
['click', 'touchstart', 'touchend', 'touchcancel', 'contextmenu'].forEach(type => {
  btn.addEventListener(type, e => console.log(e.type));
});

// what you need:
btn.oncontextmenu = e => e.preventDefault(); // prevent the context menu on long touch
btn.onclick = btn.ontouchend = btn.ontouchcancel = debounce(e => {
  console.log('Correctly handled the click event');
}, 100);

function debounce(fn, timeout=0) {
  let flag = false;
  return function() {
    if (!flag) {
      flag = true;
      setTimeout(_ => flag = false, timeout);
      fn.call(...arguments);
    }
  };
}
<button id="btn">
click me
</button>

请注意,即使单击按钮的默认操作也不会发生(例如,如果此按钮位于

中,则在长时间触摸的情况下不会提交该表单。

答案 1 :(得分:1)

所以我尝试了一下,它似乎正常工作。它也会在单击鼠标,短按和长按时触发。由于问题是关于Chrome的,因此我在Android的Chrome 71.0.3578.99上进行了测试。

首先,您需要禁止用户在按钮上进行选择,否则,将不会长按。

第二,为什么每个人都非常关心释放鼠标/手指在其他地方?开始单击/轻击然后移开/滑动的唯一原因是用户改变了主意,并且不想执行按钮所执行的任何操作。

最后,在我的代码中,根据需要删除并添加了事件侦听器。这仅是由于问题的结构:此代码在台式机和移动设备上均可使用。在支持鼠标和触摸屏的设备上也不会中断。

回答要点的问题:

  • 是的,一次至少两个-clicktouchstart / touchend
  • 是的,您需要使用它来防止短按两次触发(如果将其从我的代码中删除,则将看到它在短按时触发touchend,然后触发click事件)。您可能希望假设触发一次触摸事件,那么用户没有鼠标连接到设备-在这种情况下,只需删除clickFunc()之外的//Your code的全部内容即可: 。

const button = document.getElementById("button");
function clickFunc(e){
  if(e.touches){
    e.preventDefault(); //Try to comment it out: double triggers on short tap
    button.removeEventListener("touchend", clickFunc);
    button.addEventListener("click", clickFunc);
    console.log('tapped!');
  }else{
	  console.log('clicked!');
  }
  //
  //Your code here
}
function touchFunc(){
  button.removeEventListener("click", clickFunc);
  button.addEventListener("touchend", clickFunc);
}
window.onload=function(){
  button.addEventListener("click", clickFunc);
  button.addEventListener("touchstart", touchFunc);
}
#button{
  user-select: none; /*find crossbrowser solution!*/

  /*For testing purposes*/
  margin-top: 100px;
  margin-left: 100px;
  font-size: 48px; 
  padding: 10px 0; 
}
<!DOCTYPE html>
<html lang="en">
<head>
	<title>Clicks and Touches</title>
</head>
<body>
	<button id="button">Click me!</button>
</body>
</html>

答案 2 :(得分:0)

处理触摸和鼠标单击而无需两次触发:

function handleInteraction(evt) {
  evt.preventDefault()
  console.log('interacted')
  // your code...
}
var el = document.getElementById('el');
el.addEventListener('touchstart', handleInteraction)
el.addEventListener('click', handleInteraction)
#el {
  cursor: pointer;
  width: 100px;
  height: 100px;
  background-color: #bcd1ea;
  text-align: center;
  line-height: 100px;
  color: #246dad;
}
<div id='el'>
el
</div>