[英]Controlling vertical scrolling and horizontal swiping on a list in an iOS web app with JavaScript
我正在创建一个专门针对手机的网络应用程序(主要是iPhone,但Android和WP即将推出......)。
其中一个屏幕包含滚动的项目列表。 我希望该列表的行为类似于内置的iOS Mail应用程序。
换一种说法...
所以 - 弄清楚用户的意图是很重要的,这意味着我可能需要阻止任何响应,直到我弄清楚用户是在垂直还是水平移动她的手指。
只需在列表容器上设置这些CSS样式......
overflow-y: auto;
-webkit-overflow-scrolling: touch;
......我得到了#1和#2。 所以,我需要弄清楚如何实现#3。
我的第一个想法是实现这样的东西(伪代码)......
touchstart
事件侦听器。 在回调中,存储用户的起始触摸位置的x坐标和y坐标。 touchmove
事件侦听器。 在回调中,计算用户手指移动的距离(例如,delta_x和delta_y) 我希望我在touchstart
或touchmove
使用event.preventDefault()来控制何时开始滚动。 例如,
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);
但是 - 这不起作用。 无论你移动多远,列表都不会滚动。
显然 - 我误解了触发滚动的内容,以及event.preventDefault()在此上下文中应该做什么。
那么 - 有没有办法完成我追求的目标?
我希望有一个纯粹的JavaScript解决方案(所以我更好地理解它),但jQuery方法可以。 我绝对希望尽可能避免使用jQuery插件/库/框架......
提前致谢!
我不建议重新发明轮子。 有许多库支持手势检测。 其中,我建议使用Hammer.js来检测触摸事件。
它没有任何依赖关系,它很小,只有3.96 kB缩小+ gzipped!
而这一切都与处理触摸事件无关。
在您的情况下,Hammer内置了swipe
检测功能。
您可以通过指定以下内容来自定义默认滑动手势:
速度:识别前所需的最小速度( 单位为每毫秒px )
和更多。
下面是一个简单的例子 ( Stack Snippet似乎有一些模拟触摸事件的问题,小提琴工作正常 ):
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>
如果您对学习触摸事件的工作方式更感兴趣而不是完成工作,那么我建议您深入了解Hammer。
对于那些不能使用jQuery的人来说,还有一个小的Hammer.js 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中,布尔变量“touching”设置为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;
}
与您的方法类似,我会在触摸移动时确定delta-x和delta-y,我将其命名为distanceX和distanceY。 当这是第一次“移动”时,我确定了触摸方向,可以是右,左,上或下。 登记的下一个动作只能保持在这个初始的竖立状态,即上/下或左/右。 因此,如果初始方向例如是“右”,则用户只能水平滑动(向左或向右)但从不向上/向下滑动。
由于我的代码被设计为水平移动幻灯片,我只对水平移动感兴趣( - >在您可以看到的代码片段中,我更新了方向(左,右),存储了新的xPosition并移动了幻灯片这个方向),但它不应该太难以适应垂直滚动。
我有相同的任务,并编写了一个纯Javascript lib swiped.js,用于在列表上进行水平滑动
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.