admin管理员组

文章数量:1201375

function bubble(content, triggerElm){
  this.element = $('<div class="bubble" />').html(content);
  this.element.css(.....) // here is positioned based on triggerElm
}

bubble.prototype.show = function(){
  $(document).on('click', this._click.bind(this));
  this.element.css(....)
};

bubble.prototype.hide = function(){
  $(document).off('click', this._click.bind(this));
  this.element.css(....)
};  

bubble.prototype._click = function(event){
  console.log('click', this);

  if(this.element.is(event.target) || (this.element.has(event.target).length > 0))
    return true;

  this.hide();
};

var b = new bubble();
b.show();
b.hide();

I keep seeing click in the console, so the click does not unbind. But if I remove the bind() call the click is unbinded. Does anyone know why? I need a way to be able to change "this" inside my test function, that's why I'm using bind().

function bubble(content, triggerElm){
  this.element = $('<div class="bubble" />').html(content);
  this.element.css(.....) // here is positioned based on triggerElm
}

bubble.prototype.show = function(){
  $(document).on('click', this._click.bind(this));
  this.element.css(....)
};

bubble.prototype.hide = function(){
  $(document).off('click', this._click.bind(this));
  this.element.css(....)
};  

bubble.prototype._click = function(event){
  console.log('click', this);

  if(this.element.is(event.target) || (this.element.has(event.target).length > 0))
    return true;

  this.hide();
};

var b = new bubble();
b.show();
b.hide();

I keep seeing click in the console, so the click does not unbind. But if I remove the bind() call the click is unbinded. Does anyone know why? I need a way to be able to change "this" inside my test function, that's why I'm using bind().

Share Improve this question edited May 22, 2019 at 13:31 Brian Tompsett - 汤莱恩 5,88372 gold badges61 silver badges133 bronze badges asked Mar 2, 2015 at 0:07 ElfyElfy 1,8636 gold badges21 silver badges40 bronze badges 0
Add a comment  | 

6 Answers 6

Reset to default 6

The problem is that this._click.bind() creates a new function every time it's called. In order to detach a specific event handler, you need to pass in the original function that was used to create the event handler and that's not happening here, so the handler is not removed.

If there are only going to be a few bubbles in your app, you could and simply not use this. That will remove a lot of the confusion about what this is referring to and ensure that each bubble retains a reference to its own click function that can be used to remove the event as needed:

function bubble(content, triggerElm) {
    var element = $('<div class="bubble" />').html(content);
    element.css(.....); // here is positioned based on triggerElm

    function click(event) {
        console.log('click', element);
        if (element.is(event.target) || 
            element.has(event.target).length > 0) {
            return true;
        }
        hide();
    }

    function show() {
        $(document).on('click', click);
        element.css(....);
    }

    function hide() {
        $(document).off('click', click);
        element.css(....);
    } 

    return {
        show: show,
        hide: hide
    };
}

var b1 = bubble(..., ...);
b1.show();

var b2 = bubble(..., ...);
b2.show();

See how this frees you from using contrivances like .bind() and underscore-prefixed methods.

One option would be to namespace the event:

$(document).on('click.name', test.bind(this));
$(document).off('click.name');

Example Here

try use jQuery's proxy to get a unique reference of your function.

In this way, when you call $.proxy(test, this), it will check if this function has already been referenced before. If yes, proxy will return you that reference, otherwise it will create one and return it to you. So that, you can always get your original function, rather than create it over and over again (like using bind).

Therefore, when you call off(), and pass it the reference of your test function, off() will remove your function from click event.

And also, your test function should be declared before use it.

var test = function(){
      console.log('click');
};    

$(document).on('click', $.proxy(test, this));
$(document).off('click', $.proxy(test, this));

http://jsfiddle.net/aw50yj7f/

Please read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

bind creates a new function therefore doing $(document).on('click', test.bind(this)); is like $(document).on('click', function(){}); and each time you execute it you invoke a new anonymous function thus you dont have a reference to unbind.

If you would do something like:

var test = function(){
     console.log('click');
};

var newFunct = test.bind(this);
$(document).on('click', newFunct );
$(document).off('click', newFunct );

It should work fine

e.g: http://jsfiddle.net/508dr0hv/

Also - using bind is not recommended, its slow and not supported in some browsers.

rather than binding this to the event, send this as a parameter:

$("#DOM").on("click",{
'_this':this
},myFun);

myFun(e){
 console.info(e.data._this);
$("#DOM").off("click",myFun);
}

If you've run into this problem when using classes, an alternative I found is to replace the handler definition with an assignment to a bound function:

//Replace this
onclick(e) {
    //...
}

//With this:
onclick = function(e) {
    //...
}.bind(this);

It's not very pretty, but it does save a refactor if you've already written the code.

本文标签: javascriptjQuery off() is not unbinding events when using bindStack Overflow