jQuery(滑动与触摸)pageX 和 pageY 不断返回 0
Posted
技术标签:
【中文标题】jQuery(滑动与触摸)pageX 和 pageY 不断返回 0【英文标题】:jQuery (Swipe vs. Touch) pageX and pageY keep returning 0 【发布时间】:2011-10-29 07:59:48 【问题描述】:我正在 iPhone 上玩 touchstart 和 touchend 事件。我构建了一个带有 div 的示例页面,如果您触摸它并滚动页面,它应该返回开始和结束位置的 y 坐标。
链接:http://jsbin.com/ibemom/2
jQuery:
var touchStartPos;
$('.theDiv')
.bind('touchstart', function(e)
touchStartPos = e.pageY;
)
.bind('touchend', function(e)
alert(touchStartPos + ' | ' + e.pageY)
)
但是,当我在 iPhone 上加载该页面时,警报一直将这两个值报告为零。有人发现我的东西有什么问题吗?
更新:
我在 jQuery Mobile 项目中偶然发现了这段代码:https://github.com/jquery/jquery-mobile/issues/734
它的评论突出了:
// (in ios event.pageX and event.pageY are always 0 )
它并没有说为什么是这样的,但至少我找到了其他人看到同样的事情。将挖掘该页面上的示例代码以查看解决方案是否存在。
更新二:
嗯,看了上面链接中的示例代码后,看起来这将返回一个实际值:
e.originalEvent.touches[0].pageY
关键是,我现在意识到这不是我需要的。它返回我在将事件附加到与 html 文档相关的对象中触摸的区域的 Y 偏移量......而不是浏览器窗口。
我的目标是找出触摸在屏幕上从哪里开始,在哪里结束……然后比较这些值。如果它们有很大不同,那么我们假设执行了滑动......而不是触摸。
更新三:
我还找到了对这些示例的引用:
e.originalEvent.touches[0].pageX
event.targetTouches[0].pageY
虽然我似乎也无法让这些工作。两者都返回未定义的错误。
更新四:
看起来一种解决方案是在文档本身上跟踪 offset()。我可以对文档应用一个 touchend 事件,然后检查它的偏移量。
这个问题是我的 touchend 事件将首先在我的页面上的元素上触发,然后它会在文档上触发它(冒泡)。所以在我需要弄清楚在对象 touchend 事件上要做什么之前,我实际上无法确定它是触摸还是滑动。
还在琢磨这个……
【问题讨论】:
很奇怪,不知道手机,但点击效果很好jsfiddle.net/nH2PU 我希望这不会是一个大问题。 ;) android (2.2.2) 中似乎也发生了同样的事情 【参考方案1】:好的,快速回答是当手指离开屏幕时您无法检测到触摸 (touchend
)。
我的第一个例子证明:http://jsfiddle.net/Y4fHD/
现在是解决方法。或者叫它你想要的。也许不检测touchend
事件是有意义的,因为触摸已经结束了。
在touchmove
事件上绑定处理程序:http://jsfiddle.net/Y4fHD/1/
var endCoords = ;
$(document.body).bind("touchmove", function(event)
endCoords = event.originalEvent.targetTouches[0];
);
然后使用变量endCoords
来判断最后一次触摸
$(document.body).bind("touchend", function(event)
$('p').text("Your end coords is: x: " + endCoords.pageX + ", y: " + endCoords.pageY);
);
好的,试着轻点您的设备!然后错误仍然会发生:为什么?因为你没有移动你的触摸。
如果我们都准备好在touchstart
定义endCoords
变量,我们就在那里:http://jsfiddle.net/Y4fHD/2/
var endCoords = ;
$(document.body).bind("touchstart touchmove", function(event)
endCoords = event.originalEvent.targetTouches[0];
);
然后使用变量endCoords
来确定最后一次触摸
$(document.body).bind("touchend", function(event)
$('p').text("Your end coords is: x: " + endCoords.pageX + ", y: " + endCoords.pageY);
);
现在尝试点按您的设备!
一些最后的注释将是:制作变量:startCoords
和 endCoords
,然后在 touchend
事件中使用它们:http://jsfiddle.net/Y4fHD/3/
var startCoords = , endCoords = ;
$(document.body).bind("touchstart", function(event)
startCoords = endCoords = event.originalEvent.targetTouches[0];
);
$(document.body).bind("touchmove", function(event)
endCoords = event.originalEvent.targetTouches[0];
);
$(document.body).bind("touchend", function(event)
$('p').text("Your touch on the axis: " + Math.abs(startCoords.pageX-endCoords.pageX) + "x, " + Math.abs(startCoords.pageY-endCoords.pageY) + "y");
);
注意:
以上示例均未经过测试,希望它有效!Math.abs
给了我一个数字的绝对值,例如:-5 变为 5
【讨论】:
我发现在上一个例子中,你在 "$('p').text("Your touch on the axis..." 行上写了两次 Y 轴的绝对值。 @Arabam 现在已修复。想想两年后就会发现类型错误:) 感谢您提及event.originalEvent
- 在 Android 上,原始事件是抑制 targetTouches 属性并破坏一切!有趣的是,这在 iOS 上不是问题——这使得调试变得更加困难。【参考方案2】:
有一段简化的代码用于检测 .myelement 的滑动手势,最初是滑块库
$(function()
var diff, tchs, del = 150,
clk = function(el)
if ( typeof(tchs) !== 'object' ) return; //we have nothing to do
if ( (diff - tchs[tchs.length - 1].pageX) < 0 ) //swipe right
else if ( (diff - tchs[tchs.length - 1].pageX) > 0 ) //swipe left
;
$('.myelement').bind('touchstart touchmove', function(ev)
var oev = ev.originalEvent, el = $(this);
switch( ev.type.charAt(5) )
case 's': //touch start
diff = oev.pageX;
window.setTimeout(clk, del, el);
break;
case 'm': //touch move
tchs = oev.touches;
break;
);
);
UPD:顺便说一下,当我使用 MobiOne 版本 2.0.0M2 测试中心软件时,它已经按照我的预期设置了 touchend pageX 值,所以这听起来很糟糕,如果你没有快速访问可能很容易混淆真实设备。
UPD2:好的,受到正面反馈的启发 :) 实现了有点复杂的版本,它允许检测左右滑动,它还需要清理,但你明白了。
$(function ()
var ftch, // first touch cache
lck = Math.sin(Math.PI / 4); //lock value, sine of 45 deg configurable
var defSwipeDir = function (el, tchs) // need define swaping direction, for better UX
if (typeof (tchs) !== 'object') return 0; // check if there was any movements since first touch, if no return 0
var ltch = tchs[tchs.length - 1], // last touch object
dx = ltch.pageX - ftch.pageX,
dy = ltch.pageY - ftch.pageY,
hyp = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)),
sin = dy / hyp,
cos = dx / hyp,
dir;
if (Math.abs(cos) >= lck) // left or right swape
dir = cos > 0 ? 'r' : 'l';
else // up or down
dir = sin < 0 ? 'u' : 'd';
el.trigger('swipe', dir); // trigger custom swipe event
return dir; // and return direction too
$('.myelementTouchDetection').on('touchstart touchmove swipe', function (ev, d)
var oev = ev.originalEvent,
myelementTouchDetection = $(this),
dir; // you may know swipes on move event too
switch (ev.type)
case 'touchstart':
ftch = oev;
break;
case 'touchmove':
dir = defSwipeDir(myelementTouchDetection, oev.touches);
return false // cancel default behaiviour
break;
case 'swipe':
switch (d)
case 'r': // swipe right
console.log('swipe right');
break;
case 'l': // swipe left
console.log('swipe left');
break;
case 'u': // swipe up
console.log('swipe up');
break;
case 'd': // swipe down
console.log('swipe down');
break;
break;
)
);
【讨论】:
【参考方案3】:上面的 NULL 答案对我来说非常有用,只是您不能在 touchstart-bound 函数中将 startCoords 分配给 endCoords。然后它们指向同一个对象,这样当 endCoords 更新时,startCoords 也会更新。当 touchend 事件触发时,startCoords 将始终等于 endCoords。
更新了下面的代码。这对我在 iOS 6.0 上使用 Safari 的 iPad 3 有效。还进行了编辑以修复数学和显示错误并在 touchend-bound 函数中删除 Math.abs()。还在 touchmove-bound 函数中添加了一个 event.preventDefault() 调用,这样它们也可以在 iOS 上的 Google Chrome 上运行。
var startCoords = , endCoords = ;
$(document.body).bind("touchstart", function(event)
endCoords = event.originalEvent.targetTouches[0];
startCoords.pageX = event.originalEvent.targetTouches[0].pageX;
startCoords.pageY = event.originalEvent.targetTouches[0].pageY;
);
$(document.body).bind("touchmove", function(event)
event.preventDefault();
endCoords = event.originalEvent.targetTouches[0];
);
$(document.body).bind("touchend", function(event)
$('p').text("Your touch on the axis: " + (endCoords.pageX-startCoords.pageX) + "x, " + (endCoords.pageY-startCoords.pageY) + "y");
);
【讨论】:
【参考方案4】:这对我有用....
$('.someClass').bind('touchmove',function(e)
e.preventDefault();
var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
var elm = $(this).offset();
var x = touch.pageX - elm.left;
var y = touch.pageY - elm.top;
if(x < $(this).width() && x > 0)
if(y < $(this).height() && y > 0)
//your code here
);
【讨论】:
以上是关于jQuery(滑动与触摸)pageX 和 pageY 不断返回 0的主要内容,如果未能解决你的问题,请参考以下文章
jQuery中 pageX,clientX,offsetX,layerX的区别