Предотвращение событий эмуляции мыши (т. Е. Щелчка) из событий касания в Mobile Safari / iPhone с использованием Javascript - PullRequest
39 голосов
/ 23 мая 2010

Создавая одностраничное приложение Javascript с интерактивными элементами DOM, я обнаружил, что последовательность "mouseover-mousemove-mousedown-mouseup-click" происходит в виде группы после последовательности событий "touchstart-touchmove-touchend".

Я также обнаружил, что можно предотвратить события "mouse*-click", выполнив "event.preventDefault()" во время события touchstart, но только тогда, а не во время touchmove и touchend. Это странный дизайн, потому что во время touchstart невозможно узнать, намерен ли пользователь перетащить или провести пальцем, или просто коснуться / щелкнуть элемент.

Я закончил тем, что установил флаг ignore_next_click где-то, привязанный к отметке времени, но это, очевидно, не очень чисто.

Кто-нибудь знает лучший способ сделать это, или мы что-то упустили?

Обратите внимание, что хотя "щелчок" может быть распознан как последовательность "touchstart-touchend" (т.е. без "touchmove"), существуют определенные вещи, такие как фокус ввода с клавиатуры, которые могут произойти только во время правильного click событие.

Ответы [ 9 ]

4 голосов
/ 07 апреля 2012

Я сталкивался с подобными проблемами при создании кроссплатформенных приложений HTML5 / JS. Единственным реальным ответом для меня было protectDefault на событиях касания и собственное управление событиями касания и событиями щелчка, перетаскивания и т. Д. В соответствии с моей логикой. Это звучит намного сложнее, чем на самом деле, но имитируемые события щелчка / мыши прекрасно работают в большинстве мобильных браузеров.

Нажмите и дополнительная мышь последовательность - все это для вашего удобства (и совместимости). Мое эмпирическое правило - если это для вашего удобства, но это неудобно, лучше убить его.

Что касается полей ввода, им нужны только события касания. Я убил события щелчка / мыши и все еще мог позволить мобильным браузерам корректно реагировать на прикосновения к входам. Если он по-прежнему вызывает проблемы, вы можете изменить обработчик событий так, чтобы он подавлял события только на входах:

function touchHandler(event) {
    var shouldIgnore = event.target != null 
          && ( event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea" );

    if(!shouldIgnore) e.preventDefault();
}
3 голосов
/ 04 апреля 2013

Я сам принял решение, так как в другом месте не нашел достаточного решения:

   var isTouch = ('ontouchstart' in window);

   function kill(type){
     window.document.body.addEventListener(type, function(e){
       e.preventDefault();
       e.stopPropagation();
       return false;
     }, true);
   }

   if( isTouch ){
     kill('mousedown');
     kill('mouseup');
     kill('click');
     kill('mousemove');
   }

Проверка isTouch позволяет всем работать как обычно на устройствах ввода с мышью, но убивает эмулированные события в Safari / iOS. Хитрость заключается в том, чтобы использовать useCapture = true в вызове addEventListener, поэтому мы собираем все события мыши на странице, не взламывая код во всем веб-приложении. Смотрите документацию по этой функции здесь: https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener

Edit:

Теперь, когда библиотеки для решения этой проблемы лучше, вы можете просто использовать что-то вроде Fastclick в качестве альтернативы (https://github.com/ftlabs/fastclick).

2 голосов
/ 18 марта 2015

Если вам необходимо поддерживать устройства, которые поддерживают как мышь, так и касание, другое решение заключается в использовании прослушивателя событий захвата, который останавливает все события мыши, которые происходят либо

  • с задержкой после события касания
  • в той же позиции, что и событие касания
  • для того же целевого элемента, что и событие касания

Информация (время, положение или целевой элемент) события касания может быть записана в другом приемнике событий захвата.

1 голос
/ 15 апреля 2019

Просто предотвратите событие touchend. Он позволит браузеру прокручивать страницу, когда вы касаетесь элемента, но не позволяет ему генерировать события искусственной мыши.

element.addEventListener('touchend', event => {
  event.preventDefault();
});
1 голос
/ 23 ноября 2018

Это решение позволяет вам прослушивать PointerEvents, если они существуют, затем TouchEvents, если они существуют, затем MouseEvents, если ни один из двух других не существует. Mobile Safari будет по-прежнему поднимать touchstart и mousedown, но вы будете слушать только touchstart.

if (window.PointerEvent) {                                  /* decent browsers */
    etouch.addEventListener('pointerdown', (e) => {
        console.log('pointerdown');
    });
}
else if (window.TouchEvent) {                               /* mobile Safari */
    etouch.addEventListener('touchstart', (e) => {
        console.log('touchstart');
    });
}
else {                                                      /* desktop Safari */
    etouch.addEventListener('mousedown', (e) => {
        console.log('mousedown');
    });
}
1 голос
/ 02 февраля 2018

Обертывание вашего кода только для мыши в функцию Window.matchesMedia - самый чистый способ, который я нашел.

if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) {
    el.addEventListener('mouseover', ev => {
         // mouse handler, no simulated hover
    }
}

Это работает для предотвращения симулированных зависаний, но, вероятно, также предотвратит симулированные щелчки.

Примечание. Начиная с версии 58 в Firefox должна быть включена опция -moz-touch.

0 голосов
/ 09 июля 2019

Использование 'pointerwhatever' вместо 'mousewhatever', похоже, отлично работает в современных браузерах (2019).

, т. Е. Они изобрели способ иметь одинаковый код для всех устройств ввода.

0 голосов
/ 07 марта 2019

Вы можете попытаться выйти из функции при событиях click, mousedown или mouseup, когда устройство поддерживает сенсорные события.

use.addEventListener("click",function(e){

  // EXIT FUNCTION IF DEVICE SUPPORTS TOUCH EVENTS
  if ("ontouchstart" in document.documentElement) return false;

  // YOURMOUSEONLY CODE HERE

});
0 голосов
/ 05 августа 2013

Создание быстрых кнопок для мобильных веб-приложений имеет решение этой проблемы.

Также имейте в виду, что при использовании IE10 protectDefault () не останавливает события ghost / синтетической / эмулированной мыши после события MSPointerDown, поэтому настоящее кросс-браузерное решение сложнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...