document.addEventListener('touchstart', function (e) {
e.preventDefault();
});
Не используйте свойство ontouchmove
для регистрации обработчика событий, так как вы рискуете перезаписать существующие обработчики событий. Вместо этого используйте addEventListener (см. Примечание об IE на странице MDN).
Помните, что предотвращение по умолчанию для события touchstart
на window
или document
отключит прокрутку нисходящих областей.
Чтобы предотвратить прокрутку документа, но оставить все остальные события без изменений, по умолчанию использовать первое touchmove
событие, следующее за touchstart
:
var firstMove;
window.addEventListener('touchstart', function (e) {
firstMove = true;
});
window.addEventListener('touchmove', function (e) {
if (firstMove) {
e.preventDefault();
firstMove = false;
}
});
Причина, по которой это работает, заключается в том, что мобильный Safari использует первый шаг, чтобы определить, прокручивается ли тело документа. Я понял это, разрабатывая более сложное решение.
В случае, если это когда-нибудь перестанет работать, более сложным решением является проверка элемента touchTarget
и его родителей и составление карты направлений, по которой можно прокрутить. Затем используйте первое событие touchmove
, чтобы определить направление прокрутки и посмотреть, будет ли оно прокручивать документ или целевой элемент (или любой из родительских элементов целевого элемента):
var touchTarget,
touchScreenX,
touchScreenY,
conditionParentUntilTrue,
disableScroll,
scrollMap;
conditionParentUntilTrue = function (element, condition) {
var outcome;
if (element === document.body) {
return false;
}
outcome = condition(element);
if (outcome) {
return true;
} else {
return conditionParentUntilTrue(element.parentNode, condition);
}
};
window.addEventListener('touchstart', function (e) {
touchTarget = e.targetTouches[0].target;
// a boolean map indicating if the element (or either of element parents, excluding the document.body) can be scrolled to the X direction.
scrollMap = {}
scrollMap.left = conditionParentUntilTrue(touchTarget, function (element) {
return element.scrollLeft > 0;
});
scrollMap.top = conditionParentUntilTrue(touchTarget, function (element) {
return element.scrollTop > 0;
});
scrollMap.right = conditionParentUntilTrue(touchTarget, function (element) {
return element.scrollWidth > element.clientWidth &&
element.scrollWidth - element.clientWidth > element.scrollLeft;
});
scrollMap.bottom =conditionParentUntilTrue(touchTarget, function (element) {
return element.scrollHeight > element.clientHeight &&
element.scrollHeight - element.clientHeight > element.scrollTop;
});
touchScreenX = e.targetTouches[0].screenX;
touchScreenY = e.targetTouches[0].screenY;
disableScroll = false;
});
window.addEventListener('touchmove', function (e) {
var moveScreenX,
moveScreenY;
if (disableScroll) {
e.preventDefault();
return;
}
moveScreenX = e.targetTouches[0].screenX;
moveScreenY = e.targetTouches[0].screenY;
if (
moveScreenX > touchScreenX && scrollMap.left ||
moveScreenY < touchScreenY && scrollMap.bottom ||
moveScreenX < touchScreenX && scrollMap.right ||
moveScreenY > touchScreenY && scrollMap.top
) {
// You are scrolling either the element or its parent.
// This will not affect document.body scroll.
} else {
// This will affect document.body scroll.
e.preventDefault();
disableScroll = true;
}
});
Причина, по которой это работает, заключается в том, что мобильный Safari использует первое касание, чтобы определить, выполняется ли прокрутка тела документа или элемента (или любого из родительских элементов целевого элемента), и придерживается этого решения.