Javascript 检测触摸设备上的左/右滑动,但允许向上/向下滚动
我需要检测并对左/右滑动做出反应,但我想让用户能够在同一个元素上滚动,因此只要他只向左/向右移动手指,最大上/下移动X像素,它就不应该滚动,但当他超过X时,它应该滚动 所以我所做的是:Javascript 检测触摸设备上的左/右滑动,但允许向上/向下滚动,javascript,jquery,touch,swipe,Javascript,Jquery,Touch,Swipe,我需要检测并对左/右滑动做出反应,但我想让用户能够在同一个元素上滚动,因此只要他只向左/向右移动手指,最大上/下移动X像素,它就不应该滚动,但当他超过X时,它应该滚动 所以我所做的是: var startX, startY, $this = $(this); function touchmove(event) { var touches = event.originalEvent.touches; if (touches && touches.le
var startX, startY, $this = $(this);
function touchmove(event) {
var touches = event.originalEvent.touches;
if (touches && touches.length) {
var deltaX = touches[0].pageX - startX;
var deltaY = touches[0].pageY - startY;
if (Math.abs(deltaY) > 50) {
$this.html('X: ' + deltaX + '<br> Y: ' + deltaY + '<br>TRUE');
$this.unbind('touchmove', touchmove);
return true;
} else {
$this.html('X: ' + deltaX + '<br> Y: ' + deltaY);
event.preventDefault();
}
}
}
function touchstart(event) {
var touches = event.originalEvent.touches;
if (touches && touches.length) {
startX = touches[0].pageX;
startY = touches[0].pageY;
$this.bind('touchmove', touchmove);
}
//event.preventDefault();
}
var startX,startY,$this=$(this);
功能触摸移动(事件){
var touchs=event.originalEvent.touchs;
如果(接触和接触长度){
var deltaX=touchs[0]。pageX-startX;
var deltaY=touchs[0]。pageY-startY;
如果(数学绝对值(deltaY)>50){
$this.html('X:'+deltaX+'
Y:'+deltaY+'
TRUE');
$this.unbind('touchmove',touchmove);
返回true;
}否则{
$this.html('X:'+deltaX+'
Y:'+deltaY);
event.preventDefault();
}
}
}
功能触摸启动(事件){
var touchs=event.originalEvent.touchs;
如果(接触和接触长度){
startX=touchs[0].pageX;
startY=touchs[0].pageY;
$this.bind('touchmove',touchmove);
}
//event.preventDefault();
}
但我不恢复在“如果”情况下滚动的能力
谢谢你的提示。我自己编写了触摸处理程序事件。也许这对你有帮助 它检查: 快速点击:“fc” 向左轻扫:“swl” 向右滑动:“swr” 向上滑动:“swu” 向下滑动:“社署” 每个检查都会初始化相应的事件。但您可以滚动并执行正常执行的任何其他操作。你只是有一些新的活动 您需要swl swr,我还建议使用fc(快速点击)进行点击事件。。。它比普通的点击要快得多
window.onload = function() {
(function(d) {
var
ce = function(e, n) {
var a = document.createEvent("CustomEvent");
a.initCustomEvent(n, true, true, e.target);
e.target.dispatchEvent(a);
a = null;
return false
},
nm = true,
sp = {
x: 0,
y: 0
},
ep = {
x: 0,
y: 0
},
touch = {
touchstart: function(e) {
sp = {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
},
touchmove: function(e) {
nm = false;
ep = {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
},
touchend: function(e) {
if (nm) {
ce(e, 'fc')
} else {
var x = ep.x - sp.x,
xr = Math.abs(x),
y = ep.y - sp.y,
yr = Math.abs(y);
if (Math.max(xr, yr) > 20) {
ce(e, (xr > yr ? (x < 0 ? 'swl' : 'swr') : (y < 0 ? 'swu' : 'swd')))
}
};
nm = true
},
touchcancel: function(e) {
nm = false
}
};
for (var a in touch) {
d.addEventListener(a, touch[a], false);
}
})(document);
//EXAMPLE OF USE
var h = function(e) {
console.log(e.type, e)
};
document.body.addEventListener('fc', h, false); // 0-50ms vs 500ms with normal click
document.body.addEventListener('swl', h, false);
document.body.addEventListener('swr', h, false);
document.body.addEventListener('swu', h, false);
document.body.addEventListener('swd', h, false);
}
要处理多个元素和相同的函数。。。只需添加一个处理程序
所以如果你有
<ul id="ul"><li>1</li><li>2</li><li>3</li></ul>
同样适用于fc和swr
ios中存在一个bug:不要使用alert()。。它将执行2次。所有这些代码都需要改进(就像您可以在触摸操作中找到的大多数代码一样) 在玩触摸事件时,请记住,用户有多个手指,触摸具有标识符,并且
触摸
列表表示表面上的所有当前触摸,即使是未移动的触摸
因此,这个过程相对简单:
event.originalEvent.touchs
属性,而是event.originalEvent.changedtouchs
one)。使用event.originalEvent.changedtouchs[0]注册其标识符。标识符和要查找的触摸属性(pageX
/pageY
或clientX
/clientY
与DOMElement.getBoundingClientRect()方法结合使用)
event.originalEvent.changedTouches.identifiedTouch(标识符)
的changedTouches列表中。如果未返回任何内容,则表示用户移动了另一个触摸屏(而不是您正在寻找的触摸屏)。还可以注册触摸属性以查找和执行任何您想要的操作如果你想做得更强壮,考虑多个触摸(不仅仅是一个)来观察。< /P> 有关TouchEvent、TouchList和Touch on的更多信息:
接受的答案中有一个“bug”。如果您在Android上不使用Chrome,而是使用内置浏览器或“网络视图”(适用于html5混合应用程序),则不会检测到滑动 我发现由于正常的滚动行为,事件没有触发。因此,在touchmove中添加“e.preventDefault();”可以修复它,也可以修复已接受答案中Eric Fuller的修复 这是一个很好的剪断,但在移动网络应用程序或网站中,这可能会导致糟糕的滚动口吃,因为触摸事件会一直被观察到 所以我决定建造一些新的东西。它不像有新的活动听众那样舒适,但它足以满足我的需要,而且性能良好function detectswipe(el,func) {
swipe_det = new Object();
swipe_det.sX = 0;
swipe_det.sY = 0;
swipe_det.eX = 0;
swipe_det.eY = 0;
var min_x = 20; //min x swipe for horizontal swipe
var max_x = 40; //max x difference for vertical swipe
var min_y = 40; //min y swipe for vertical swipe
var max_y = 50; //max y difference for horizontal swipe
var direc = "";
ele = document.getElementById(el);
ele.addEventListener('touchstart',function(e){
var t = e.touches[0];
swipe_det.sX = t.screenX;
swipe_det.sY = t.screenY;
},false);
ele.addEventListener('touchmove',function(e){
e.preventDefault();
var t = e.touches[0];
swipe_det.eX = t.screenX;
swipe_det.eY = t.screenY;
},false);
ele.addEventListener('touchend',function(e){
//horizontal detection
if ((((swipe_det.eX - min_x > swipe_det.sX) || (swipe_det.eX + min_x < swipe_det.sX)) && ((swipe_det.eY < swipe_det.sY + max_y) && (swipe_det.sY > swipe_det.eY - max_y)))) {
if(swipe_det.eX > swipe_det.sX) direc = "r";
else direc = "l";
}
//vertical detection
if ((((swipe_det.eY - min_y > swipe_det.sY) || (swipe_det.eY + min_y < swipe_det.sY)) && ((swipe_det.eX < swipe_det.sX + max_x) && (swipe_det.sX > swipe_det.eX - max_x)))) {
if(swipe_det.eY > swipe_det.sY) direc = "d";
else direc = "u";
}
if (direc != "") {
if(typeof func == 'function') func(el,direc);
}
direc = "";
},false);
}
myfunction(el,d) {
alert("you swiped on element with id '"+el+"' to "+d+" direction");
}
如果检测到刷卡,将使用参数元素id和“l、r、u、d”(左、右、上、下)调用函数“myfunction”
示例:在触摸仍在移动时检测左右移动 这是通过保存最后一个位置和使用超时来完成的,用于在触摸移动停止后擦除最后一个位置
var currentX;
var lastX = 0;
var lastT;
$(document).bind('touchmove', function(e) {
// If still moving clear last setTimeout
clearTimeout(lastT);
currentX = e.originalEvent.touches[0].clientX;
// After stoping or first moving
if(lastX == 0) {
lastX = currentX;
}
if(currentX < lastX) {
// Left
} else if(currentX > lastX){
// Right
}
// Save last position
lastX = currentX;
// Check if moving is done
lastT = setTimeout(function() {
lastX = 0;
}, 100);
});
var-currentX;
var-lastX=0;
var lastT;
$(文档).bind('touchmove',函数(e){
//如果仍在移动,请清除上次设置超时
清除超时(lastT);
currentX=e.originalEvent.touchs[0].clientX;
//回采或首次移动后
如果(lastX==0){
lastX=当前X;
}
如果(当前x<最后x){
//左
}否则如果(currentX>lastX){
//对
}
//保存最后位置
lastX=当前X;
//检查移动是否完成
lastT=setTimeout(函数(){
lastX=0;
}, 100);
});
受@cocco I的启发,创建了一个更好的(非最小化)版本:
或者jquery风格
$("article").on("gesture-down", function (e) { ... });
谢谢@T.J.Crowder,添加了@Raphael:您在任何地方声明了吗?是的,在顶部添加了@T.J.Crowder这太复杂了,我无法理解:/另一个解决方案是使用swipeleft上的事件侦听器,swiperight等是专为低cpu设备设计的,因为它可以防止许多检查和计算,并且只使用您看到的短代码,无需添加第三方库,也不会覆盖设备的本机滚动系统,这可能会使我的解决方案不那么落后
detectswipe('an_element_id',myfunction);
detectswipe('an_other_element_id',my_other_function);
var currentX;
var lastX = 0;
var lastT;
$(document).bind('touchmove', function(e) {
// If still moving clear last setTimeout
clearTimeout(lastT);
currentX = e.originalEvent.touches[0].clientX;
// After stoping or first moving
if(lastX == 0) {
lastX = currentX;
}
if(currentX < lastX) {
// Left
} else if(currentX > lastX){
// Right
}
// Save last position
lastX = currentX;
// Check if moving is done
lastT = setTimeout(function() {
lastX = 0;
}, 100);
});
(function(d) {
// based on original source: https://stackoverflow.com/a/17567696/334451
var newEvent = function(e, name) {
// This style is already deprecated but very well supported in real world: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent
// in future we want to use CustomEvent function: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
var a = document.createEvent("CustomEvent");
a.initCustomEvent(name, true, true, e.target);
e.target.dispatchEvent(a);
a = null;
return false
};
var debug = false; // emit info to JS console for all touch events?
var active = false; // flag to tell if touchend should complete the gesture
var min_gesture_length = 20; // minimum gesture length in pixels
var tolerance = 0.3; // value 0 means pixel perfect movement up or down/left or right is required, 0.5 or more means any diagonal will do, values between can be tweaked
var sp = { x: 0, y: 0, px: 0, py: 0 }; // start point
var ep = { x: 0, y: 0, px: 0, py: 0 }; // end point
var touch = {
touchstart: function(e) {
active = true;
t = e.touches[0];
sp = { x: t.screenX, y: t.screenY, px: t.pageX, py: t.pageY };
ep = sp; // make sure we have a sensible end poin in case next event is touchend
debug && console.log("start", sp);
},
touchmove: function(e) {
if (e.touches.length > 1) {
active = false;
debug && console.log("aborting gesture because multiple touches detected");
return;
}
t = e.touches[0];
ep = { x: t.screenX, y: t.screenY, px: t.pageX, py: t.pageY };
debug && console.log("move", ep, sp);
},
touchend: function(e) {
if (!active)
return;
debug && console.log("end", ep, sp);
var dx = Math.abs(ep.x - sp.x);
var dy = Math.abs(ep.y - sp.y);
if (Math.max(dx, dy) < min_gesture_length) {
debug && console.log("ignoring short gesture");
return; // too short gesture, ignore
}
if (dy > dx && dx/dy < tolerance && Math.abs(sp.py - ep.py) > min_gesture_length) { // up or down, ignore if page scrolled with touch
newEvent(e, (ep.y - sp.y < 0 ? 'gesture-up' : 'gesture-down'));
//e.cancelable && e.preventDefault();
}
else if (dx > dy && dy/dx < tolerance && Math.abs(sp.px - ep.px) > min_gesture_length) { // left or right, ignore if page scrolled with touch
newEvent(e, (ep.x - sp.x < 0 ? 'gesture-left' : 'gesture-right'));
//e.cancelable && e.preventDefault();
}
else {
debug && console.log("ignoring diagonal gesture or scrolled content");
}
active = false;
},
touchcancel: function(e) {
debug && console.log("cancelling gesture");
active = false;
}
};
for (var a in touch) {
d.addEventListener(a, touch[a], false);
// TODO: MSIE touch support: https://github.com/CamHenlin/TouchPolyfill
}
})(window.document);
document.body.addEventListener('gesture-right', function (e) { ... });
$("article").on("gesture-down", function (e) { ... });