Jquery, unbinding mousewheel event, then rebinding

2019-04-06 13:49发布

I've been struggling with this for a little while now.. I am using this code to monitor the mousewheel so it can be used for scrolling with a slider that I have.. however, it has an issue where the actions queue up so if you scroll with the mousewheel fast (like anyone would do normally) they build up and it causes buggy behavior.. I know about handling this sort of issue with animation, but not with a mousewheel monitor..

I want to do something like unbind the mousewheel at the start of the action (in this case, to scroll the scrollbar after mousewheel is moved) then rebind it after this, so if user does too many scrolls too fast it just ignores until the initial scroll is completed.. I tried the code below but its not rebinding so I'm not sure what I am doing wrong, any advice is appreciated.

        $("#wavetextcontainer").bind("mousewheel", function(event, delta) {

   //HERE IS WHERE EVENT IS UNBOUND:
     $("#wavetextcontainer").unbind("mousewheel");

        var speed = 10;
        var mySlider = $("#slider");
        var sliderVal = mySlider.slider("option", "value");

        sliderVal += (delta*speed);

        if (sliderVal > mySlider.slider("option", "max")) sliderVal = mySlider.slider("option", "max");
        else if (sliderVal < mySlider.slider("option", "min")) sliderVal = mySlider.slider("option", "min");

        $("#slider").slider("value", sliderVal);

        event.preventDefault();

      // HERE I WANT TO REBIND THE EVENT:
     $("#wavetextcontainer").bind("mousewheel");

});

2条回答
狗以群分
2楼-- · 2019-04-06 14:37

You need to store the function were you can reference it, like this:

function myHandler(event, delta) {
     $("#wavetextcontainer").unbind("mousewheel", myHandler);

        var speed = 10;
        var mySlider = $("#slider");
        var sliderVal = mySlider.slider("option", "value");

        sliderVal += (delta*speed);

        if (sliderVal > mySlider.slider("option", "max")) sliderVal = mySlider.slider("option", "max");
        else if (sliderVal < mySlider.slider("option", "min")) sliderVal = mySlider.slider("option", "min");

        $("#slider").slider("value", sliderVal);

        event.preventDefault();

      // HERE I WANT TO REBIND THE EVENT:
     $("#wavetextcontainer").bind("mousewheel", myHandler);    
};

$("#wavetextcontainer").bind("mousewheel", myHandler);

By doing this you can call .bind() later to the same function (you can't reference an anonymous one). You're currently trying to call .bind() without a function to handle anything, which doesn't work. This also has the added advantage of being able to pass that same function reference to .unbind() so it unbinds only that handler, not any mousewheel handler.


Alternatively, do this without un/re-binding, like this:

$("#wavetextcontainer").bind("mousewheel", function (event, delta) {
  event.preventDefault();
  if($.data(this, 'processing')) return; //we're processing, ignore event

  $.data(this, 'processing', true);
  var speed = 10;
  var mySlider = $("#slider");
  var sliderVal = mySlider.slider("option", "value");

  sliderVal += (delta*speed);

  if (sliderVal > mySlider.slider("option", "max")) sliderVal = mySlider.slider("option", "max");
  else if (sliderVal < mySlider.slider("option", "min")) sliderVal = mySlider.slider("option", "min");

  $("#slider").slider("value", sliderVal);
  $.data(this, 'processing', false);
});

This just uses $.data() to store a "we're working" data entry with the element, if anything hits this handler while it's true, it just returns and ignores the event.

查看更多
forever°为你锁心
3楼-- · 2019-04-06 14:52

In this situation that's a lot of unnecessary binding/unbinding, which is more difficult and more inefficient than it has to be. Unbinding is great to free up resources when an action isn't needed anymore, or won't be needed for a while; but for a split second of not wanting your code to run unbinding/rebinding is a lot of overhead, just use a variable to determine whether to honor the mouse-wheel or not, and just toggle it true and false as needed. Likely no need to use jquery data either, just a quicker var defined outside the function.

var doMouseWheel = true;
$("#wavetextcontainer").bind("mousewheel", function(event, delta)
{
        // it'll just not do anything while it's false
        if (!doMouseWheel)
            return;

        // here's where you were unbinding, now just turning false
        doMouseWheel = false;

        // do whatever else you wanted

        // here's where you were rebinding, now just turn true
        doMouseWheel = true;
});

though honestly the logic of disabling the scroller only while the couple lines above processes is a bit flawed, you musta been a programmer that dealt with multithreading languages a lot :) In js it's not even possible for another event to fire in the middle of a function's lines of code, so I assume you'd rather shut it off for a period of time (and that would apply whether you use a variable or bind/unbind):

var doMouseWheel = true;
$("#wavetextcontainer").bind("mousewheel", function(event, delta)
{
        // it'll just not do anything while it's false
        if (!doMouseWheel)
            return;

        // here's where you were unbinding, now just turning false
        doMouseWheel = false;

        // do whatever else you wanted

        // here's where you were rebinding, now wait 200ms and turn on
        setTimeout(turnWheelBackOn, 200);
});

function turnWheelBackOn() { doMouseWheel = true; }
查看更多
登录 后发表回答