Прослушивание mousedown AND touchstart на устройствах, которые используют сенсорный экран и мышь (например, Surface)

Итак, я столкнулся с интересной проблемой при работе с веб-приложением для Microsoft Surface.

Я хочу добавить прослушиватели событий, когда пользователь взаимодействует с элементом DOM. Теперь я могу сделать:

if ('ontouchstart' in document.documentElement) {
  //Attach code for touch event listeners
  document.addEventListener("touchstart" myFunc, false);
} else {
  //Attach code for mouse event listeners
  document.addEventListener("mousedown" myFunc, false);
}

Если у устройства не было ввода мыши, эта проблема была бы простой, и вышеуказанный код работал бы очень хорошо. Но на поверхности (и на многих новых компьютерах с Windows 8) есть BOTH сенсорный и мышь. Таким образом, приведенный выше код будет работать только тогда, когда пользователь коснется устройства. Слушатели событий мыши никогда не будут прикреплены.

Итак, я подумал, что я мог бы это сделать:

if ('ontouchstart' in document.documentElement) {
  //Attach code for touch event listeners
  document.addEventListener("touchstart" myFunc, false);
}
//Always attach code for mouse event listeners
document.addEventListener("mousedown" myFunc, false);

Устройства, которые не поддерживают touch, не будут привязаны к событиям, но устройство, использующее touch, зарегистрирует свои обработчики. Проблема с этим заключается в том, что myFunc() будет вызываться дважды на сенсорном устройстве:

  • myFunc() будет срабатывать при поднятии "touchstart".
  • Поскольку сенсорные браузеры обычно проходят через сенсорный экран цикла → touchmove → touchhend → mousedown → mousemove → mouseup → click, myFunc() будут снова вызваны в "mousedown"

Я рассмотрел добавление кода в myFunc(), чтобы он вызывал e.preventDefault(), но, похоже, он также блокирует touchhend, а также mousedown/mousemove/mouseup на некоторых браузерах (ссылка).

Мне не нравится делать useragent sniffers, но кажется, что сенсорные браузеры имеют вариации в том, как реализованы события касания.

Мне, должно быть, что-то не хватает, потому что кажется, что эти реализации JavaScript были решены с возможностью браузера, поддерживающего мышь и прикосновение!

Ответ 1

Для Windows 8 вы можете использовать событие "MSPointerDown".

 if (window.navigator.msPointerEnabled) {
     document.addEventListener("MSPointerDown" myFunc, false);
 }

Также добавьте в свой стиль следующее:

  html { 
    -ms-touch-action: none; /* Direct all pointer events to JavaScript code. */
  }

Подробнее см. http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx.

Ответ 2

Внутри myFunc проверьте тип события. Если он коснется, тогда сделайте e.stopPropagation().

function myFunc(e) {
    if (e.type === 'touchstart') {
        e.stopPropagation();
    }
    //the rest of your code here
}

Ответ 3

Редакция: Если вы используете jQuery, вы сможете сделать вот так:

var clickEventType=((document.ontouchstart!==null)?'mousedown':'touchstart');

$("a").bind(clickEventType, function() {
    //Do something
});

Это приведет к срабатыванию только одного из событий привязки.

Найдено здесь: Как привязать события "touchstart" и "click" , но не отвечать на оба: