2012-01-04 17 views
7

मैं बाँध का उपयोग कर रहा रोक/माउसव्हील स्क्रॉल के लिए निकल, इस अतः प्रतिक्रिया के आधार पर:jQuery उपकरण माउसव्हील से स्क्रॉल - एक स्थिति स्क्रॉल और

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

मैं डेल्टा से घटना पेड़ सुरंग रहा हूँ, केवल एक्स mousewheel मूल्यों को लक्षित करने के लिए। सब ठीक काम कर रहे हैं। जिस समस्या को मैं दूर करने की कोशिश कर रहा हूं: मैं बस एक पैनल को आगे/पीछे स्क्रॉल करना चाहता हूं, फिर स्क्रॉल करना बंद करें। वर्तमान में, मैं कदम के तुरंत बाद मूसहेल घटना को अनबाइंड कर रहा हूं, और यह प्रभावी रूप से स्क्रॉलिंग को रोकता है ... लेकिन मूसहेल घटना को अनबाइंड करने से पृष्ठ को भी जैक किया जाता है। मुझे जो चाहिए वह दिशा के लिए पहले डेल्टाएक्स मूल्य को छीनने में सक्षम होना है, फिर एक कदम बनाएं और सुनना बंद करें। क्या मुझे उत्तर के लिए ऑटोस्कोल देखने की ज़रूरत है? बाध्यकारी/अनबाइंडिंग klugy लगता है, लेकिन मैं नहीं कर सकता, मेरे जीवन के लिए, एक कदम के बाद बाहर निकलना कैसे पता चलता है, जबकि तब भी उस कदम के बाद स्क्रॉल करने में सक्षम हो रहा है।

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

चूंकि डोम पहले स्क्रॉलिंग ईवेंट के बीच अलग-अलग होने का कोई तरीका नहीं देता है और बाद वाले लोग उसी स्क्रॉलिंग गति का हिस्सा बनते हैं, हम हैं उनके बीच अंतर करने के अप्रत्यक्ष तरीकों के बारे में सोचने के लिए मजबूर होना पड़ा।

यदि आप किसी भी विशेष तत्व के माध्यम से तेजी से स्क्रॉल करते हैं, तो अनुक्रम में कई बार स्क्रॉलिंग ईवेंट निकाल दिया जाता है।

// Using mouse wheelbar 
251327626600149 
251327626600215 
251327626600265 
251327626600282 
251327626600332 
251327626600365 

// Using touchpad 
251327626626207 
251327626626225 
251327626626261 
251327626626276 
251327626626312 
251327626626345 

:

$('#exampleDiv').bind('mousewheel', function() { 
    console.log(new Date().getTime()); 
}); 

आपको लगता है कि div पर स्क्रॉल, तो आप एक कंसोल आउटपुट कि इस तरह दिखता है मिल जाएगा: निम्नलिखित कोड का उपयोग करना, हम के बारे में वास्तव में कितनी बार ऐसा होता है एक विचार प्राप्त कर सकते हैं इस आउटपुट को देखते हुए, ऐसा लगता है कि 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 बना सकते हैं, और यह देखने के लिए जांचें कि प्रत्येक बार mousescroll ईवेंट निकाल दिया गया है (एनीमेशन समाप्त होने के बाद इसे कॉलबैक में झूठा करना सुनिश्चित करें)।

यह काम करेगा, सिवाय इसके कि यह उपयोगकर्ता के लिए एक झटकेदार अनुभव प्रदान कर सकता है। कोई भी जो जल्दी से दो पैनलों के माध्यम से स्क्रॉल करना चाहता है, एनीमेशन शुरू होने के बाद भी स्क्रॉल के बीच रुकने की संभावना नहीं होगी। उपरोक्त कोड एक ही स्क्रॉलिंग गति के हिस्से के रूप में उनके सभी 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

प्रत्येक समाधान जो मैंने तैयार किया है उसे स्थापित करने में शामिल देरी की तरह। परियोजना के लिए, डिजाइन मोड ने अंततः इस मुद्दे को अस्वीकार कर दिया, लेकिन यह अभी भी मुझे परेशान कर रहा है। कल कल मुझे एक ही गेंदबाज में एक समस्या थी - समान नहीं - जिसमें मुझे एनीमा रोकने की जरूरत थी टी() विंडो आकार बदलने पर। यह इस मुद्दे पर मेरा दिमाग वापस रख दिया। मेरा मानना ​​है कि आपने जो सबसे कामुक/सबसे पुरानी चीज़ बनने के लिए प्रदान की है, वह आज तक आई है। इसके लिए, मैं आपको विजेता चिह्नित करता हूं। – wlangley

+1

बहुत बढ़िया! कोड 'सेक्सी' के टुकड़े को कॉल करना उतना ही तारीफ है जितना मैं संभाल सकता हूं। मैं आपके शुरुआती डिजाइन विचार के बारे में सोच रहा था - हालांकि क्षैतिज स्क्रॉलिंग के साथ, आप अभी भी मैक पर जेस्चर के साथ कुछ मुद्दों में भाग लेंगे (क्योंकि दो अंगुली दोनों स्क्रॉल स्वाइप करती हैं और आपको क्रोम और सफारी पर इतिहास में वापस ले जाती हैं)। मुझे अभी तक _that_ समस्या के समाधान का पता लगाना बाकी है। – pikappa

+0

500 से नीचे के मानों के साथ (एनीमेशनटाइम और शांत अवधि के बारे में बात करते हुए), यह पैटर्न काम करना बंद कर देता है। कम कीमतों के साथ अपने jsfiddle को फिर से प्रयास करें और आप उस बिंदु को देखेंगे, जहां मेरे दिमाग में, यह अपेक्षित काम करना बंद कर देता है। समाधान की सराहना की गई अगर – Ben

0

इस पर एक नज़र डालें और देखें कि आप क्या सोचते हैं। शुरू करने के लिए मैं mousheheel से बंधे नहीं होगा क्योंकि फ़ायरफ़ॉक्स इसके बजाय DOMMouseScroll का उपयोग करता है। यह एक अलग डेल्टा हैंडलर का भी उपयोग करता है जो कि अन्य सभी ब्राउज़रों द्वारा उपयोग किए जाने वाले विपरीत है। इसके बजाय jQuery की स्क्रॉल ईवेंट से जुड़ें जो व्यवहार को सामान्य करता है। यह निर्धारित करने के लिए कि क्या उपयोगकर्ता ऊपर या नीचे स्क्रॉल करता है, आप अंतिम स्क्रॉलटॉप स्थिति को ट्रैक कर सकते हैं।

मैं इस धारणा को स्वीकार कर रहा हूं कि आप अनुभागों के बीच एनिमेट कर रहे हैं। क्या कोई कॉलबैक फ़ंक्शन है जिसका उपयोग आप यह निर्धारित करने के लिए कर सकते हैं कि आपको स्क्रॉल करना चाहिए या नहीं? मैंने यह ट्रैक करने के लिए एक वैश्विक बनाया है कि तत्व वर्तमान में एनिमेट कर रहे हैं या नहीं। यदि ऐसा है तो हम फ़ंक्शन निष्पादित करने से परेशान नहीं हैं। अंत में, मैंने देखा कि स्क्रॉल एनीमेशन के लिए कॉलबैक अंतिम स्क्रॉल ईवेंट होने से पहले ट्रिगर लगता है, इसलिए मुझे वास्तव में वहां एक सेटटाइमआउट का उपयोग करना पड़ा। मुझे यह पसंद नहीं आया, लेकिन मुझे पता नहीं लगा कि कॉलबैक को ठीक से काम करने के लिए और कैसे प्राप्त किया जा सकता है।

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 है -पृष्ठ साइट, और अनुभागों के बीच स्क्रॉल कर रहा हूँ - लेकिन साइट/स्क्रॉलिंग क्षैतिज है। तो मुझे लगता है कि scrollTop के बजाय scrollLeft का उपयोग करना होगा, मुझे लगता है। लेकिन बड़ा मुद्दा यह है कि टूल्स स्क्रॉल करने योग्य ऑब्जेक्ट की एक संपत्ति है जिसे 'मूसहेल' (http://flowplayer.org/tools/demos/scrollable/plugins/index.html) कहा जाता है, और यदि मैं इसका उपयोग नहीं करता (सेट सच करने या अंत तक बांधने के लिए), माउस व्हील स्क्रॉलिंग साइट को nukes। ऐसा लगता है कि जब तक डेल्टाएक्स बदलना बंद नहीं हो जाता है तब तक कार्रवाई करने के लिए स्थगित करने का एक तरीका होना चाहिए (scrollable.move()), फिर एक बार स्थानांतरित करें। – wlangley

+0

मुझे आश्चर्य है कि .throttle() मेरी जादू बुलेट हो सकता है। http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/ – wlangley

+0

हम्म, मैं अटक गया हूँ। सुनिश्चित नहीं है कि आप इसे कैसे हल करेंगे = ( – mrtsherman

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)); 

}); 

तो, जबकि वृद्धि हुई मैं ठीक बाहर प्रिंट, अगर मैं uncomment अगर मैं = 4 प्रिंट लाइन, यह ठीक से काम नहीं करता है (आप हार्ड स्क्रॉल करने के लिए आप माउस का उपयोग कर रहे हैं तो हो सकता है, im मेरे ट्रैकपैड में कोशिश कर रहा है)। जबकि मैं इसे समझता हूं क्योंकि जब आप डेल्टा मान प्राप्त करते हैं, तो मैं लगातार बढ़ता हूं, जब आप 4 तक पहुंचते हैं तो केवल कुछ निष्पादित करते हैं और स्क्रॉल को 250ms के लिए रुकने पर ही इसका मान रीसेट कर दिया जाता है, यह कोड मुझे कम से कम दो बार या तीन बार रीसेट करने लगता है। == 4 वास्तव में दो बार या तीन बार निष्पादित करता है। शायद आप पा सकते हैं कि क्या हो रहा है। मैं लगभग वहां हूँ, बस उस बग को ठीक करने की जरूरत है।

कुछ ऐसा जोड़ने की कोशिश करें जो fadeIn, fadeOut प्रभाव में परिवर्तन करता है यदि (i == 4) कथन और इसके अधिक प्रमुख हैं।

संपादित करें:

Heres the new edited version।मूसहेल लिंक पुराना था इसलिए शायद यह अब बेहतर दिखाता है। यदि आप तेजी से आगे बढ़ते हैं, तो आप इसे झटकेदार देखते हैं ...

+0

क्या यह ओपी का उत्तर होना चाहिए या आप अपना खुद का प्रश्न पोस्ट कर रहे हैं? यह एक चर्चा मंच नहीं है। – Sparky

+0

यह एक उत्तर है। – Chandra

0

मुझे लगता है कि "पिकप्पा" द्वारा प्रदान किया गया समाधान शुद्ध सेक्सीपन है।

मेरे लिए यह फ़ायरफ़ॉक्स पर पूरी तरह से काम कर रहा था लेकिन क्रोम 26.0 के तहत स्क्रॉल करते समय मुझे "झटके" का सामना करना पड़ रहा था।एक्स

एक साधारण गंदे "पैच" उसकी अद्भुत कोड को जोड़ रहा है "return false ;" लाइन 57 और के 64 में अपने JSfiddle

संबंधित मुद्दे