我找到了这个线程,因为我有一个类似且更复杂的问题:
假设我们创建了一个带有箭头 NEXT/PREVIOUS 的启用 js 的可滚动区域,我们不仅要响应触摸和鼠标事件,还要在用户继续按下屏幕或按住他/她的鼠标时重复触发它们!
重复事件将使我的下一个按钮前进 2 个位置而不是一个!
在闭包的帮助下,一切似乎都是可能的:
(1)首先创建一个变量隔离的自调用函数:
(function(myScroll, $, window, document, undefined){
...
}(window.myScroll = window.myScroll || {}, jQuery, window, document));
(2) 然后,添加将保持内部状态的私有变量setTimeout()
:
/*
* Primary events for handlers that respond to more than one event and devices
* that produce more than one, like touch devices.
* The first event in browser's queue hinders all subsequent for the specific
* key intended to be used by a handler.
* Every key points to an object '{primary: <event type>}'.
*/
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}
(3) 事件锁功能:
function getEventLock(evt, key){
if(typeof(eventLock[key]) == 'undefined'){
eventLock[key] = {};
eventLock[key].primary = evt.type;
return true;
}
if(evt.type == eventLock[key].primary)
return true;
else
return false;
}
function primaryEventLock(evt, key){
eventLock[key].primary = evt.type;
}
(4) 附加您的事件处理程序:
function init(){
$('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
$('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
// similar for 'next*' handlers
}
触发事件mousedown
并将touchstart
在支持两者的设备上产生对处理程序的双重调用(可能首先触发触摸)。这同样适用于mouseup
和touchend
。
我们知道输入设备(实际上是整个图形环境)按顺序产生事件,所以我们不关心哪个先触发,只要将特殊键设置为私有eventLock.next.primary
和分别从处理程序和eventLock.previous.primary
捕获的第一个事件。next*()
previous*()
该键是事件类型,因此第二个,第三个等事件始终是失败者,它们不会在锁定函数的帮助下获得锁定,eventLock()
并且primaryEventLock()
。
(5) 上面可以看到事件处理器的定义:
function previousStart(evt){
// 'race' condition/repetition between 'mousedown' and 'touchstart'
if(!getEventLock(evt, 'previous'))
return;
// a. !!!you have to implement this!!!
previous(evt.target);
// b. emulate successive events of this type
pids.previous = setTimeout(closure, defaults.pressDelay);
// internal function repeats steps (a), (b)
function closure(){
previous(evt.target);
primaryEventLock(evt, 'previous');
pids.previous = setTimeout(closure, defaults.pressDelay);
}
};
function previousEnd(evt){
clearTimeout(pids.previous);
};
nextStart
和类似nextEnd
。
这个想法是,无论谁在第一个(触摸或鼠标)之后来,都不会在 的帮助下获得锁定function eventLock(evt, key)
并停在那里。
打开此锁的唯一方法是在步骤*End()
(4):previousEnd
和nextEnd
.
我还以一种非常聪明的方式处理了在会话中间连接的触摸设备的问题:我注意到连续按下的时间比只为当时的主要事件defaults.pressDelay
产生回调函数的连续调用(原因是没有end 事件处理程序终止 callabck)!
touchstart event
closure
closure
....
touchend event
我将用户使用的设备定义为主要设备,您只需按下更长的时间,您的设备就会在封闭装置的帮助下立即成为主要设备!primaryEventLock(evt, 'previous')
另请注意,执行所需的时间previous(event.target)
应小于defaults.pressDelay
.
(6) 最后,让我们暴露init()
给全局作用域:
myScroll.init = init;
您应该用previous(event.target)
手头的问题替换调用:fiddle。
另外,请注意,在(5b)处,有一个解决另一个流行问题的方法,即我们如何将参数传递给调用 from 的函数setTimeout()
,即setTimeout(previous, defaults.pressDelay)
缺少参数传递机制。