Управление вертикальной прокруткой и горизонтальным считыванием списка в веб-приложении iOS с помощью JavaScript
Я создаю веб-приложение, специально предназначенное для телефонов (в первую очередь iPhone, но Android и WP находятся на горизонте...).
один из экранов содержит прокручиваемый список элементов. Я хотел бы, чтобы список вел себя аналогично встроенному почтовому приложению iOS.
другими словами...
- если пользователь касается списка и перемещается вверх или вниз, список прокручивается по вертикали.
- если пользователь щелкает вверх или вниз, список прокручивается вертикально с естественным импульсом
- если пользователь касается списка и перемещается только left-конкретный элемент скользит влево, показывая кнопку удаления.
- главное - список должен прокручиваться или элемент должен скользить, НО НИКОГДА ОБА.
So-важно выяснить, каковы намерения пользователя, что означает, что мне, вероятно, нужно предотвратить любой ответ, пока я не пойму ли пользователь двигает ее пальцем вертикально или горизонтально.
просто установив эти стили CSS в контейнере списка...
overflow-y: auto;
-webkit-overflow-scrolling: touch;
... Я получаю #1 & #2 выше. Итак, мне нужно выяснить, как реализовать #3.
моей первой мыслью было реализовать что-то вроде этого (псевдокод)...
- создать
touchstart
прослушиватель событий в контейнере списка. В обратном вызове сохраните X-и y-координаты начального касания пользователя позиция. - создать
touchmove
прослушиватель событий в контейнере списка. В обратном вызове выясните, как далеко переместился палец пользователя (например, delta_x и delta_y) - если delta_x и delta_y оба меньше, чем 10 пикселей - ничего не делайте (не прокручивайте список или не сдвигайте элемент) - поскольку мы еще не выяснили, планирует ли пользователь двигаться вверх/вниз или влево / вправо.
- если или delta_x или delta_y более 10 пикселей - мы можем предположить, что пользователь переместился достаточно далеко, чтобы выразить свое намерение. Если delta_y > delta_x, предположим, что она движется вверх/вниз и позволяет списку прокручиваться, но не скользит элемент. Если delta_x > delta_y, предположим, что она движется влево / вправо, поэтому мы должны позволить элементу скользить, но не позволять списку прокручиваться.
Я ожидал, что буду использовать event.метод preventDefault() в touchstart
или touchmove
в контроль, когда прокрутка должна начаться. Е. Г.,
div.addEventListener("touchstart", function(e) {
touchStart = {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
}, false);
div.addEventListener("touchmove", function(e) {
touchNow = {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
var
dx = touchStart.x - touchNow.x,
dy = touchStart.y - touchNow.y;
if ((Math.abs(dx) < 10) && (Math.abs(dy) < 10)) {
// prevent scrolling
e.preventDefault();
} else if (Math.abs(dx) > Math.abs(dy) < 10) {
// moving right/left - slide item
} else {
// moving up/down - allow scrolling
}
}, false);
однако-это не работает. Независимо от того, как далеко вы двигаетесь, список никогда свитки.
очевидно-я не понимаю, что вызывает прокрутку и какое событие.в этом контексте предполагается, что preventDefault ().
Итак-есть ли способ выполнить то, что я ищу?
Я надеюсь на чистое решение JavaScript (поэтому я понимаю его лучше), но подход jQuery было бы неплохо. Я определенно надеюсь избежать плагина / библиотеки / фреймворка jQuery, если это вообще возможно...
спасибо заранее!
3 ответов
Я не предлагаю изобретать велосипед. Существует несколько библиотек, которые поддерживают обнаружение жестов. Из которых я предлагаю использовать молоток.js для обнаружения события касания.
он не имеет никаких зависимостей, и он маленький, только 3.96 kB minified + gzipped!
и все дело в обработке touch событий, ничего больше.
в вашем случае, Hammer имеет встроенный swipe
обнаружение.
вы можете настроить жест салфетки по умолчанию, указав:
- направление: направление, в котором вы хотите обнаружить жеста (подробнее)
- порог: минимальное расстояние, необходимое для распознавания
-
скорость: минимальная скорость, необходимая для распознавания (блок в px в ms)
и больше.
ниже простой пример: (фрагмент стека, похоже, имеет некоторые проблемы с эмуляцией сенсорных событий, скрипка работает нормально):
var myElement = document.getElementById("container");
var hammertime = new Hammer(myElement, {});
hammertime.get('swipe').set({
direction: 2 // 2 stands for left
})
hammertime.on('swipe', function(event) {
event.target.querySelector(".delete").classList.add("show");
});
* {
margin: 0;
padding: 0;
}
#container {
width: 250px;
height: 300px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
background: dodgerblue;
}
#list {
height: 100%;
list-style: none;
}
#list li {
position: relative;
box-sizing: border-box;
width: 100%;
height: 50px;
border: 2px solid #fff;
}
#list li span.delete {
display: inline-block;
position: absolute;
left: 250px;
width: 50px;
height: 40px;
line-height: 40px;
margin: 3px;
text-align: center;
background: #fff;
transition: left 0.5s ease-in;
}
#list li span.delete.show {
left: 170px;
}
<script src="http://cdn.jsdelivr.net/hammerjs/2.0.4/hammer.min.js"></script>
<div id="container">
<ul id="list">
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
</ul>
</div>
Если вам больше интересно узнать , как работает сенсорное событие, а не получить работу, то я предлагаю посмотреть под капотом молотка.
есть немного молоток.JS и jQuery плагин также, для тех, кто не может расстаться с jQuery.
у меня была аналогичная проблема, когда я реализовывал слайд-шоу. Это решение, которое сработало для меня, надеюсь, оно поможет вам:
function touchStart(event){
if (!event) event = window.event;
if(!touched){
touched = true;
var touchObj = event.changedTouches[0];
touchXPos = parseInt(touchObj.clientX);
touchYPos = parseInt(touchObj.clientY);
}
return false;
}
когда пользователь касается экрана, cooridnate позиции хранятся в touchXPos, touchYPos и логическая переменная "Touch" имеет значение true.
function touchMove(event){
if (!event) event = window.event;
if(touched){
var touchObj = event.changedTouches[0];
var distanceX = touchXPos - parseInt(touchObj.clientX);
var distanceY = touchYPos - parseInt(touchObj.clientY);
if(!touchDirection) {
if(Math.abs(distanceX) > Math.abs(distanceY)){
if (distanceX > 0) touchDirection = "right";
else if (distanceX < 0) touchDirection = "left";
}
else{
if (distanceY > 0) { touchDirection = "up"; }
else if (distanceY < 0) {touchDirection = "down"; }
}
}
if (((touchDirection == "right") )|| ((touchDirection == "left"))){
//update touchDirection
if(Math.abs(distanceX) > Math.abs(distanceY)){
if (distanceX > 0) touchDirection = "right";
else if (distanceX < 0) touchDirection = "left";
}
touchXPos = parseInt(touchObj.clientX);
slideshow_mask.scrollLeft += distanceX;
}
else if (((touchDirection == "up") ) || ((touchDirection == "down") )){
return false;
}
event.preventDefault();
return false;
}
подобно вашему подходу, я определяю Дельта-x и Дельта-y всякий раз, когда движется прикосновение, которое я назвал distanceX и distanceY. Когда это первый " ход " я определить touchdirection, что может быть вправо, влево, вверх или вниз. Следующее движение, которое регистрируется, может остаться только в течение этого начального Копли, т. е. вверх/вниз или влево/вправо. Таким образом, если начальное направление было, например, "вправо", пользователь может скользить только горизонтально (влево или вправо), но никогда вверх/вниз.
поскольку мой код был разработан для перемещения слайд-шоу по горизонтали, меня просто заинтересовало горизонтальное движение (- >в фрагменте кода Вы можете видеть, что я обновил направление (слева, справа), сохранил новую xPosition и переместил слайд-шоу в этом направлении), но не должно быть слишком сложно адаптировать его к вертикальной прокрутке.
У меня была такая же задача, и я написал чистый Javascript lib спер.js горизонтальная прокрутка списка