【问题标题】:What is the most reliable way to detect clicks (or touches) on both desktop and mobile devices?在桌面和移动设备上检测点击(或触摸)的最可靠方法是什么?
【发布时间】:2019-06-17 16:16:17
【问题描述】:

我正在订阅button 元素上的click 事件。如果您点击按钮,这似乎在移动设备上有效,但如果您按住它一段时间然后释放它,它不会触发。至少在我最近使用 Chrome 的 Android 手机上是这样。

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

  • 我需要订阅多个事件吗?哪些?
  • 如果我订阅多个事件,我需要preventDefault()?

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

【问题讨论】:

  • 可能是mouseup 事件?如果你使用 jQuery,你可以尝试使用 jQuery-mobile 库。
  • 我认为触摸设备上的长按相当于右键单击,它会触发contextmenu 事件。
  • @Bamar mouseup 不好:stackoverflow.com/questions/14805225/…。您可以在其他地方释放鼠标。而且我拒绝为这种平凡的任务添加 jquery mobile :)
  • 也许touchend 可以为你工作。

标签: javascript google-chrome


【解决方案1】:

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

首先,您需要抑制用户对按钮的选择,否则将无法执行长按。

其次,为什么每个人都如此关心在其他地方释放鼠标/手指?开始单击/点击然后移动/滑开的唯一原因是用户改变了主意并且不想执行按钮说它执行的任何内容。

最后,在我的代码中,我根据需要删除和添加事件侦听器。这仅仅是因为问题结构:此代码适用于桌面设备和移动设备。它也不会在支持鼠标和触摸屏的设备上中断。

用要点回答问题:

  • 是的,至少同时有两个 - click 和 touchstart/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】:

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

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

    为了得到这个,你需要监听 touchend 事件,与 mouseup 不同,如果你在你之后将光标移到元素之外,它也会触发开始点击,但如果您在外部开始点击然后将光标移到元素上,则不会触发,对于 touchcancel 事件,该事件可能会在用户释放触摸之前触发一点(但这是我们能得到的最新活动......)。

    现在,为了避免 click 和 touchend/touchcancel 事件在同一个操作上触发,您需要 debounce 你的事件处理程序(即强制它在给定的时间间隔内只运行一次),并且可能还防止 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>

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

    中,则在长按的情况下不会提交表单。

    【讨论】:

    【解决方案3】:

    在没有双重触发的情况下处理触摸和鼠标点击:

    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>

    【讨论】:

      猜你喜欢
      • 2012-08-31
      • 2019-01-26
      • 1970-01-01
      • 2011-06-16
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      相关资源
      最近更新 更多