Невозможно предотвратить "touchmove" из окна прокрутки на iOS

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

К сожалению, это не работает в Mobile Safari. Окно продолжает прокручиваться под нашим элементом. Проблема звучит точно так же, как ошибка Webkit, описанная в https://bugs.webkit.org/show_bug.cgi?id=163207, но эта проблема предположительно была исправлена в iOS 10.3, тогда как я запускаю 11.3.

touchforcestart и вызов preventDefault, похоже, не позволяют прокручивать окно, но мы вызываем его в touchstart, который кажется "слишком поздним", поскольку окно все еще прокручивается. Прокрутка только предотвращается в следующий раз, touchstart вызывается touchstart.

Любые идеи о том, что происходит? Мы сбиты с толку, потому что это явно ошибка, но, похоже, она была исправлена некоторое время назад.

Ответ 1

Недавно я столкнулся с этой проблемой. Вам необходимо передать { passive: false } при регистрации touchmove событий touchmove. например

document.addEventListener('touchmove', function(e) {
    e.preventDefault();
}, { passive: false });

Это связано с тем, что прослушиватели событий с сенсорными сообщениями теперь по умолчанию пассивны в Safari 11.1, который поставляется вместе с iOS 11.3. Это изменение задокументировано в примечаниях к выпуску Safari 11.1:

Веб-интерфейсы

  • [...]
  • Обновленные корневые файлы для прослушивания сообщений о событии для использования пассивного режима улучшают производительность прокрутки и уменьшают количество сбоев.

Ответ 2

Вам нужно привязать preventDefault к двум событиям: touchmove и touchforcechange, чтобы заставить его работать в ios 11, например

document.addEventListener('touchmove', this.preventDefault, {passive: false});
document.addEventListener('touchforcechange', this.preventDefault, {passive: false});

И вы должны связать их перед началом сенсорного запуска

Если вы связываете их внутри обработчика touchstart или dragStart, они могут только предотвратить прокрутку при следующем перетаскивании.