Как предотвратить "навигацию по истории превышения прокрутки", не предотвращая сенсорный запуск?
Я использую навигацию на основе смахивания, и у меня возникают проблемы с Chrome.
Недавно реализованная функция "Навигация по истории с избыточной прокруткой" запускается при перетаскивании страницы вправо, вызывая откат назад (к "истории -1"). Чтобы предотвратить это, я должен был бы позвонить .preventDefault()
на touchstart
, но это также отключает все от нажатия ссылок на прокрутку. Как предотвратить события пользовательского интерфейса браузера, не мешая стандартной странице?
Полное отключение этой функции путем установки соответствующего флага в Chrome устраняет проблему, но не является практичным для общедоступного приложения. хром:// флаги /#overscroll-история-навигация
4 ответа
В конце концов я нашел решение:
Хром стреляет как минимум touchstart
а также touchmove
до перескрутки. Отслеживая направление этих событий, избыточная прокрутка может быть отфильтрована от обычной прокрутки.
Я написал код для этой проблемы Hammer.js.
Я использовал
html, body {
width: 100%;
height: 100%;
margin: 0;
overscroll-behavior: contain;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior
Это 'touchmove', вам нужно будет stopPropagation() И preventDefault() внутри обратного вызова, вы можете вызвать все, что вам нужно, для проверки прокрутки и вашей навигации.
- слушать
onscroll
событие в контейнере и сохранить значение "scrollLeft"this.offsetX = event.currentTarget.scrollLeft;
- слушать
onwheel
событие в том же контейнере и использовать этот обработчик
var offset = 0;
document.getElementById("1")
.addEventListener("scroll", function(event) {
offset = event.currentTarget.scrollLeft;
});
document.getElementById("1")
.addEventListener("wheel", function(event) {
// if we reach the left side of the scrollable content, and we scroll further -> block the event
if (offset === 0 && event.deltaX <= 0) {
event.preventDefault();
}
});
.container {
width: 100%;
background-color: blue;
overflow: auto;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.element {
display: inline-block;
min-width: 100px;
height: 50px;
margin: 10px;
background-color: red;
}
<div id="1" class="container">
<div class="element">
1
</div>
<div class="element">
2
</div>
<div class="element">
3
</div>
<div class="element">
4
</div>
<div class="element">
5
</div>
<div class="element">
6
</div>
<div class="element">
7
</div>
<div class="element">
8
</div>
</div>
Чтобы оставить прокрутку по вертикали рабочим и перемещать элементы по горизонтали, вам нужно проверить, больше ли перемещается вдоль оси x, чем по оси y, сравнивая различия координат с помощью Math.abs(), затем решите вызвать.preventDefault() в событии touchmove или нет.
Звучит немного странно, но я думаю, что это единственный способ управлять этой функцией бегемота "Навигация по истории Overscroll". BLE.
$(function () {
function extract(e) {
if (e.changedTouches) {
e = e.changedTouches;
if (e['0'])
e = e['0'];
}
return e;
}
var div = $('div').html('Drag me left and right and see that Overscroll is disabled & drag me up and down to see that scroll still works<br /><br /><br />'.repeat(300));
var di = div.get(0); // get native dom element
var startx, lastx, lasty, l = false, active = false;
di.addEventListener("touchstart", function (e) {
active = true;
e = extract(e);
// init
lastx = e.pageX;
lasty = e.pageY;
l = parseInt(div.css('left'), 10);
startx = e.pageX;
}, false);
di.addEventListener("touchmove", function (ee) {
if (active) {
var e = extract(ee);
// check if preventDefault to cancel Overscroll history navigation only if it's needed
if (Math.abs(lastx - e.pageX) > Math.abs(lasty - e.pageY)) {
ee.preventDefault();
}
// update x y to next above calculation
lastx = e.pageX;
lasty = e.pageY;
// repositioning
div.css({left: (l + (e.pageX - startx))+'px'})
}
}, false);
di.addEventListener("touchend", function (e) {
active = false;
}, false);
});
Полный пример для тестирования на сенсорных устройствах: DEMO