由於DOM不提供任何區分第一個滾動事件觸發和後來的碰巧是同一個滾動動作的一部分,我們被迫考慮區分它們的間接方法。
如果您快速滾動瀏覽任何特定元素,滾動事件將按順序被多次觸發。使用下面的代碼,我們可以得到關於究竟是如何發生的頻率一個想法:
$('#exampleDiv').bind('mousewheel', function() {
console.log(new Date().getTime());
});
滾動時在該專區,你會得到一個控制檯輸出看起來像這樣:
// Using mouse wheelbar
251327626600149
251327626600215
251327626600265
251327626600282
251327626600332
251327626600365
// Using touchpad
251327626626207
251327626626225
251327626626261
251327626626276
251327626626312
251327626626345
看看這個輸出,看起來好像mousescroll
事件通常在彼此的20ms和60ms之間的某個地方被觸發。爲了安全起見,我們將採取100毫秒的上限。這是非常豐富的,因爲我們可以用它來區分作爲同一動作的一部分的滾動事件和可能由用戶區別並故意發起的滾動事件。
你可以從這裏做的是創建一個全局可訪問的'timestamp'變量,每次觸發一個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();
}
});
這實際上忽略了是他們之前所有,但用戶已停頓100毫秒後重新開始工作的初始事件後觸發的所有mousescroll
事件。
這將解決您的問題,除非您的scrollToSomeOtherDiv()
函數涉及某種耗時的動畫。當然,你可以創建一個全局布爾值isAnimating
,並在每次觸發一個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。
每一個解決方案,我還設計了有關設置一些對於這個項目來說,設計模組最終否定了這個問題,但它仍然困擾着我。就在昨天,我在同一個球場出現了一個問題 - 不是相似的 - 我需要停止一個動畫te()在窗口大小調整。它讓我回想起這個問題。我相信你所提供的是我迄今爲止遇到的最性感/最有可能的事情。爲此,我標記你是贏家。 – wlangley 2012-01-27 18:30:29
太棒了!調用一段「性感」的代碼與我所能處理的差不多是一種讚美。儘管我正在考慮你的初始設計理念 - 通過水平滾動,你仍然會遇到一些手勢在Mac上的問題(因爲兩個手指滑動滾動並在Chrome和Safari中回到歷史記錄中)。我還沒有找出_that_問題的解決方案。 – pikappa 2012-01-28 06:41:46
值低於500(談論animationTime和quietPeriod)時,此模式停止工作。再次嘗試使用較低值的jsfiddle,您會發現在我的腦海中,它按預期停止工作。解決方案讚賞如果有任何 – Ben 2013-12-24 18:40:41