Javascript: любые способы обхода Chrome для Android, чтобы отключить touchmove и коснуться прослушивателей событий, кроме использования event.preventDefault()?
При использовании прослушивателей событий с событиями touchmove и touchhend я не могу заставить Chrome для Android распознавать те события, если я не впервые использовал event.preventDefault(); ранее в коде. Если я не хочу блокировать функциональность прокрутки по умолчанию, есть ли другой способ обхода, который я могу использовать, чтобы заставить Chrome для Android признать эти события?
Пример кода:
$(document).ready(function () {
// Bind touch event listeners.
var elem = $('html').get(0);
elem.addEventListener('touchstart', function (e) { console.info('"touchstart" detected. Coordinates - ' + getCoord(e)); });
elem.addEventListener('touchmove', function (e) { console.info('"touchmove" detected. Coordinates - ' + getCoord(e)); });
elem.addEventListener('touchend', function (e) { console.info('"touchend" detected. Coordinates - ' + getCoord(e)); });
function getCoord(e) {
var touch = false;
if (e.touches.length > 0) {
touch = e.touches[0];
} else {
touch = e.changedTouches[0];
}
if (touch) {
return 'x: ' + touch.pageX + ', y: ' + touch.pageY;
}
}
Пример скрипки здесь: http://jsfiddle.net/jQ2VS/1/
Ответы
Ответ 1
Google Chrome будет запускать событие touchcancel
около 200 миллисекунд после touchstart
, если он считает, что пользователь выполняет панорамирование/прокрутку и вы не вызываете event.preventDefault()
.
Предполагая, что вы хотите перехватить события горизонтального касания и позволить событиям вертикального касания вызвать панорамирование/прокрутку, обходным путем было бы следующее:
- В
touchstart
сохраните координаты в переменной и установите iteration
в 0.
- Для каждого события
touchmove
установите iteration
в iteration
+1.
- Когда
iteration
равно 4 (просто "магическое число", которое, как мне показалось, было надежным в моей настройке), вычислите общие дельты смещения касания для осей x и y.
EDIT: на мобильных устройствах вы получите только одно касание без события .preventDefault()
- Если смещение по оси x > смещение оси y * 3, то пожар event.preventDefault(). (Это гарантирует, что жест в значительной степени горизонтальный).
Нижняя сторона этого заключается в том, что пользователь может либо прокручивать влево/вправо, либо прокручивать вверх/вниз.
Ответ 2
Наконец, я нашел решение (чисто js) даже в случае, если вы можете использовать его для прокрутки:
var swipe = function() {
var touchX, touchY, movX, movY, go;
function prevent(e){
e.preventDefault();
}
function start(e) {
go = false;
document.addEventListener("touchmove", prevent, false);
touchX = e.touches[0].pageX;
touchY = e.touches[0].pageY;
}
function move(e) {
movX = e.touches[0].pageX - touchX;
movY = e.touches[0].pageY - touchY;
if(!go) {
(Math.abs(movY) < Math.abs(movX)) ? go = true : stop(e);
} else {
/* *************** */
// cast your spell
/* *************** */
}
}
function stop(e) {
document.removeEventListener("touchmove", prevent, false);
}
document.addEventListener("touchstart", start, true);
document.addEventListener("touchmove", move, true);
document.addEventListener("touchend", stop, true);
document.addEventListener("touchleave", stop, true);
document.addEventListener("touchcancel", stop, true);
}
Надеюсь на эту помощь.
Ответ 3
Самый простой ответ заключается в том, что вы должны предотвратитьDefault для первого события touchmove, иначе они будут отменены.
Ответ 4
Я обнаружил, что предотвращение работы touchcancel прекрасное.
Ответ 5
Принятый ответ неверен.
В Android, если preventDefault не установлен на touchstart, устройство предполагает собственную прокрутку, и больше никаких событий касания не отправляются в webview. Если параметр preventDefault установлен, вся естественная прокрутка отключена.
Существует прокладка для создания событий прокрутки с естественной прокруткой здесь: https://github.com/TNT-RoX/android-swipe-shim