Подтвердить что ты не робот

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

Выполняя одностраничное Javascript-приложение с интерактивными элементами DOM, я обнаружил, что последовательность "mouseover-mousemove-mousedown-mouseup-click" происходит в последовательности после последовательности событий < <21 > .

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

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

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

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

4b9b3361

Ответ 1

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

element.addEventListener('touchend', event => {
  event.preventDefault();
});

Ответ 2

У меня возникли проблемы с использованием кросс-платформенных приложений HTML5/JS. Единственный реальный ответ для меня состоял в том, чтобы предотвратить Default на событиях касания и фактически управлять состояниями касания и стрелять, перетаскивать и т.д. События самостоятельно по моей логике. Это звучит намного сложнее, чем есть на самом деле, но перемешанные события click/mouse отлично работают на большинстве мобильных браузеров.

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

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

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

    if(!shouldIgnore) e.preventDefault();
}

Ответ 3

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

   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).

Ответ 4

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

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

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

Ответ 5

Обертывание кода только для мыши в функцию 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.

Ответ 6

Это решение позволяет вам прослушивать 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');
    });
}

Ответ 7

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

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

Ответ 8

Вы можете попытаться выйти из функции при событиях 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

});

Ответ 9

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

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