由于 DOM 不提供任何方法来区分触发的第一个滚动事件和恰好属于同一滚动运动一部分的后续滚动事件,因此我们被迫考虑区分它们的间接方法。
如果快速滚动任何特定元素,则会按顺序多次触发滚动事件。使用以下代码,我们可以了解这种情况发生的确切频率:
$('#exampleDiv').bind('mousewheel', function () {
console.log(new Date().getTime());
});
当您滚动该 div 时,您将获得如下所示的控制台输出:
// Using mouse wheelbar
251327626600149
251327626600215
251327626600265
251327626600282
251327626600332
251327626600365
// Using touchpad
251327626626207
251327626626225
251327626626261
251327626626276
251327626626312
251327626626345
看看这个输出,似乎mousescroll
事件通常在 20 毫秒到 60 毫秒之间的某个时间间隔内触发。为了安全起见,我们将上限设为 100 毫秒。这是非常有用的,因为我们可以使用它来区分属于同一操作的滚动事件和可能由用户故意发起的不同滚动事件。
您可以从这里做的是创建一个全局可访问的“时间戳”变量,每次更新它mousescroll
事件被触发,无论成功与否。像这样的东西:
var timeStamp = new Date().getTime();
$('#exampleDiv').bind('mousewheel', function (event) {
var timeNow = new Date().getTime();
// Need to prevent the default scrolling behavior
event.preventDefault();
// If the last mousescroll happened less that 100 ms ago, update
// timeStamp and do nothing
if (timeNow - timeStamp < 100) {
timeStamp = timeNow;
return;
} else {
timeStamp = timeNow;
scrollToSomeOtherDiv();
}
});
这实际上忽略了所有mousescroll
在所有事件之前的初始事件之后触发的事件,但在用户暂停 100 毫秒后再次开始工作。
这可以解决您的问题,除非您的scrollToSomeOtherDiv()
函数涉及某种耗时的动画。你当然可以创建一个全局布尔值isAnimating
,并检查每次 a 是否为真mousescroll
事件被触发(确保在动画结束后在回调中将其设置为 false)。
这确实可行,但可能会给用户带来不和谐的体验。即使在看到动画开始后,想要快速滚动两个面板的人也可能不会在滚动之间暂停。上面的代码将看到它们的所有mousescroll
事件作为同一滚动运动的一部分并继续忽略它们!
在这种情况下,您可以简单地使用动画时间作为阈值。一旦动画开始,您就设置一个时间戳,然后忽略所有mousescroll
那段时间发生的事件。我在这里写了一个例子:http://jsfiddle.net/Sg8JQ/
相关代码在这里:
var lastAnimation = 0;
var animationTime = 1000; // in ms
var quietPeriod = 500; // in ms, time after animation to ignore mousescroll
function scrollThis(event, delta, deltaX, deltaY) {
var timeNow = new Date().getTime();
// change this to deltaX/deltaY depending on which
// scrolling dir you want to capture
deltaOfInterest = deltaY;
if (deltaOfInterest == 0) {
// Uncomment if you want to use deltaX
// event.preventDefault();
return;
}
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < quietPeriod + animationTime) {
event.preventDefault();
return;
}
if (deltaOfInterest < 0) {
if ($('.active').next('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').next('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
} else {
if ($('.active').prev('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').prev('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
}
}
// Note: mousewheel() is defined in the mousewheel plugin by Brandon Aaron
// You could do without it, but you'd need to adjust for firefox and webkit
// separately.
//
// You couldn't use $(document).scroll() because it doesn't allow you to
// preventDefault(), which I use here.
$(document).mousewheel(scrollThis);
我还包括了quietPeriod
这是超出动画时间的时间,在此期间您要继续忽略mousescroll
事件。如果您希望滚动在动画完成后立即“响应”,您可以将其设置为 0。