Невозможно запретить `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.

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


person Matthew Gertner    schedule 26.03.2018    source источник


Ответы (2)


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

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

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

Веб-API

  • [...]
  • Обновлены прослушиватели событий касания корневого документа для использования пассивного режима, что повышает производительность прокрутки и снижает количество сбоев.
person user9576791    schedule 30.03.2018
comment
Отличный материал, спасибо! Мы добавляем наш прослушиватель touchmove в обработчик touchstart, и по какой-то причине мне кажется, что мне нужно отменить это даже (с preventDefault), чтобы touchmove отменил, даже с отключенным пассивным. С обоими событиями { passive: false } и touchstart и touchmove, отмененными после того, как мы их обработаем, похоже, он отлично работает. - person Matthew Gertner; 05.04.2018
comment
Можно ли включить прокрутку в конкретном div только внутри документа после применения этого кода? @ user9576791 - person ; 05.09.2018
comment
Как удалить этот прослушиватель событий при нажатии со страницы? @ user9576791 - person ; 05.09.2018
comment
Хорошо, но проблема в том, что вы тоже не прокручиваете страницу. - person Ivan Ferrer; 13.09.2018
comment
@MatthewGertner - значит, вы добавили: document.addEventListener('touchstart', function(e) { e.preventDefault(); }, { passive: false }); document.addEventListener('touchmove', function(e) { e.preventDefault(); }, { passive: false }); - person Todd; 11.12.2018
comment
Большое спасибо. Я продолжал видеть ответы, в которых не было пассивной части, и поэтому они не работали. - person Andy Mercer; 29.01.2019
comment
Потрясающий! пропавший passive: false сводил меня с ума на несколько часов! Спасибо! - person Teodor Sandu; 14.11.2019
comment
как передать параметр { passive: false } функции delcaration? - person oldboy; 29.12.2020

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

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

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

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

person User007    schedule 18.08.2019
comment
Этот подход сработал для нас, спасибо! - person Martijn Kooij; 24.12.2020
comment
touchforcechange? вроде работает без этого? - person oldboy; 29.12.2020