2012-01-04 93 views
7

我使用綁定/解除綁定的滾輪滾動,在此基礎上SO迴應:jQuery的工具可滾動使用鼠標滾輪 - 滾動一個位置,並停止

Jquery, unbinding mousewheel event, then rebinding it after actions are completed?

我從三角洲隧道了事件樹,僅定位X鼠標滾輪值。一切正常。我試圖克服的問題:我想簡單地向前/向後滾動ONE面板,然後停止滾動。目前,我在移動後立即解除鼠標滾輪事件,並且有效地停止了滾動...但解開鼠標滾輪事件也會將頁面插入。我需要的是能夠嗅探方向的第一個deltaX值,然後做出動作並停止聆聽。我是否需要查看自動滾動查找答案?綁定/解除綁定感覺很糟糕,但在我的生活中,我不能在一次移動後計算如何踢出,而在移動完成後仍然可以滾動。這是我的鼠標滾輪功能:

function mouseHandler(event, delta) { 
$('.homeScrollable').bind('mousewheel', mouseHandler); 

var deltaX = event.originalEvent.wheelDeltaX; 
//console.log(event.originalEvent.wheelDeltaX); 

if(deltaX <= 0) { 
    //move forward 1 screen and stop 
    scrollapi.move(1); 
    $('.homeScrollable').unbind('mousewheel', mouseHandler); 
} else if(deltaX > 0) { 
    //move backward 1 screen and stop 
    scrollapi.move(-1); 
    $('.homeScrollable').unbind('mousewheel', mouseHandler); 
} 
event.preventDefault(); 

// Rebind mousewheel event: 
$('.homeScrollable').bind('mousewheel', mouseHandler);  }; 

我也看了設置計時器,一拉:

jquery mousewheel plugin: how to fire only one function every scroll

這似乎令人難以置信的前途,但沒有去。下面是這傢伙插件頁面: http://brandonaaron.net/code/mousewheel/docs

感謝檢查出來。

回答

18

由於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。

+0

每一個解決方案,我還設計了有關設置一些對於這個項目來說,設計模組最終否定了這個問題,但它仍然困擾着我。就在昨天,我在同一個球場出現了一個問題 - 不是相似的 - 我需要停止一個動畫te()在窗口大小調整。它讓我回想起這個問題。我相信你所提供的是我迄今爲止遇到的最性感/最有可能的事情。爲此,我標記你是贏家。 – wlangley 2012-01-27 18:30:29

+1

太棒了!調用一段「性感」的代碼與我所能處理的差不多是一種讚美。儘管我正在考慮你的初始設計理念 - 通過水平滾動,你仍然會遇到一些手勢在Mac上的問題(因爲兩個手指滑動滾動並在Chrome和Safari中回到歷史記錄中)。我還沒有找出_that_問題的解決方案。 – pikappa 2012-01-28 06:41:46

+0

值低於500(談論animationTime和quietPeriod)時,此模式停止工作。再次嘗試使用較低值的jsfiddle,您會發現在我的腦海中,它按預期停止工作。解決方案讚賞如果有任何 – Ben 2013-12-24 18:40:41

0

看看這個,看看你的想法。要開始我不會綁定到mousewheel,因爲Firefox使用DOMMouseScroll來代替。這也使用一個不同的delta處理程序,它與所有其他瀏覽器使用的處理程序相反。而是綁定到jQuery的滾動事件,規範化的行爲。您可以跟蹤最後一個滾動位置,以確定用戶是向上滾動還是向下滾動。

我有點假設你正在部分之間進行動畫處理。是否有回調函數可用於確定您是否應該滾動?我創建了一個全球視圖來跟蹤元素是否正在動畫。如果是這樣,那麼我們不打擾執行該功能。最後,我注意到滾動動畫的回調似乎在最終滾動事件發生之前觸發,所以實際上我不得不在那裏使用setTimeout。我不喜歡它,但我不知道如何讓這個回調正常工作。

http://jsfiddle.net/Gj3Qy/

var lastScrollTop = 0; 
var isDoingStuff = false; 

$(document).scroll(function(event) { 
    //abandon 
    if(isDoingStuff) { return; } 

    if ($(this).scrollTop() > lastScrollTop) { 
     //console.log('down'); 
     $('.active').removeClass('active').next('div').addClass('active'); 
     isDoingStuff = true; 
     $('html,body').animate({scrollTop: $('.active').offset().top }, 1000, function() { 
      setTimeout(function() {isDoingStuff = false;}, 100); 
      console.log('off'); 
     }); 
    } else { 
     //console.log('up'); 
    } 
    lastScrollTop = $(this).scrollTop(); 
}) 
+0

你的假設是正確的 - 我有一個1頁面網站,並在部分之間滾動 - 但網站/滾動是水平的。所以我需要使用scrollLeft而不是scrollTop,我猜。但是更大的問題是工具可滾動對象的屬性名爲'mousewheel'(http://flowplayer.org/tools/demos/scrollable/plugins/index.html),如果我不使用它(設置爲真或綁定到最後),滾動鼠標滾輪來對網站進行覈查。似乎應該有一種方法推遲採取行動(scrollable.move()),直到deltaX停止更改,然後移動一次。 – wlangley 2012-01-04 21:27:21

+0

我在想如果.throttle()可能是我的靈丹妙藥。 http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/ – wlangley 2012-01-04 21:33:09

+0

嗯,我卡住了。不知道你將如何解決這個問題=( – mrtsherman 2012-01-04 21:39:15

0

所以,這是我在做什麼。它似乎工作,但仍然是越野車。

i=0; 
$("#test").mousewheel(function(event, delta) { 
    event.preventDefault(); 
    clearTimeout($.data(this, 'timer'));   

    // check if the mouse moved on right/up 
    if(delta > 0) {    
     i++;     

     // hack to execute function just once 
     if(i == 3) {     
      $('#child').fadeIn().html("<h1>next</h1>").fadeOut(); // do something once when i=4, but happening multiple times 
     }   

    } else { // check if mouse moved left/down 

     i--;     

     if(i==-3) {  
      $('#child').fadeIn().html("<h1>previous</h1>").fadeOut(); // do something once when i=-4, but happening multiple times 
     }    

    } // end if delta 

    // only execute another mousewheel scroll after some delay 
    $.data(this, 'timer', setTimeout(function() { 
     i = 0; 
    }, 100)); 

}); 

因此,儘管增加了我打印出來就好了,如果我取消了,如果我= 4打印線,它不能正常工作(可能需要滾動硬,如果你使用的是鼠標,即時通訊嘗試在我的觸控板)。雖然我瞭解它,當我不斷增加,因爲你得到的增量值,你只執行一些東西,當我達到4,只有重置它的價值,如果滾動停止250毫秒,這段代碼似乎重置我0至少兩次或三次,所以我== 4實際執行兩次或三次。也許你可以找到可能發生的事情。我幾乎在那裏,只需要修復該錯誤。

嘗試添加一些像fadeIn,fadeOut效果那樣的變化if(i == 4)語句及其更突出的內容。

編輯:

Heres the new edited version。mousewheel鏈接是舊的,所以現在可能顯示它更好。如果你移動得很快,你會看到它閃爍......

+0

這應該是一個問題的OP或者是你發佈你自己的問題呢?這不是一個討論的論壇。 – Sparky 2012-01-07 02:45:43

+0

這是一個答案。 – Chandra 2012-01-07 03:05:28

0

我認爲「pikappa」提供的解決方案是純粹的性感。

對我來說,它是在Firefox上完美工作,但我在Chrome 26.0下滾動時遇到「閃爍」。X

一個簡單髒「補丁」以他驚人的代碼加入「返回false;」在線57和他的jsfiddle