jQuery的工具可滚动使用鼠标滚轮 - 滚动一个位置,并停止

问题描述:

我使用绑定/解除绑定的滚轮滚动,在此基础上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

感谢检查出来。

由于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

看看这个,看看你的想法。要开始我不会绑定到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

所以,这是我在做什么。它似乎工作,但仍然是越野车。

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

我认为“pikappa”提供的解决方案是纯粹的性感。

对我来说,它是在Firefox上完美工作,但我在Chrome 26.0下滚动时遇到“闪烁”。X

一个简单脏“补丁”以他惊人的代码加入“返回false;”在线57和他的jsfiddle