how to properly unbind events in Jquery-Mobile usi

2019-08-14 09:04发布

问题:

As Jquery Mobile keeps some pages in the DOM when navigating around, a page may be visited multiple times when going back and forth.

If I'm binding to a page like below and inside this binding perform all my page logic, which includes "nested element bindings":

// listener for the page to show:
$(document).on('pagebeforeshow.register', '#register', function() {

    // stuff

    // page event bindings:
    $(document).on('click.register', '.registerSubmitter', function(e) {
        // do something
        });
    });

Going back and forth causes my nested binding to be attached multiple times.

Right now trying to work around this like so (doesn't work...):

 $(document).on('click', '.registrySubmitter', function(e) {

         if ( $(this).attr('val') != true ) {
            $(this).attr('val') == true;
            // do something
            }
     });

So I'm only allowing the first binding to pass and then I block every other binding attempt that comes along.

While this works, it's far from optimal.

Question:
How and when should event bindings be properly unbound/offed? Is there a general way (kill all) or do I have to do this binding per binding? Maybe more importantly: Is it better performance-wise to do a binding once and keep it or bind/unbind when the user comes to/leaves the page?

Thanks for input!

EDIT:
So I'm namespacing all my events and then listen for pageHide like so:

$(document).on('pagehide.register', '#register', function(){
   $(document).off('.registryEvents');
   });

While this seems to unbind, it also fires when ever I close a custom dialog/selectmenu on the page, so I'm loosing my bindings before leaving the page. So partial answer, I should use off(), but how to bind to the page really being left vs. opening and closing a select menu?

回答1:

When you use .on() like that, you are delegating the event handling to the document element, meaning you can setup that delegated event binding anytime you want because the document element is always available.

I've got two suggestions:

  • Use the pageinit or pagecreate event to only run the page-specific bindings when pages are added to the DOM and initialized. Using this method I would not delegate the event bindings within the pageinit or pagecreate event handlers because when they fire, all the elements on the pseudo-page are in the DOM:

.

$(document).on('pageinit', '#register', function() {
    //note that `this` refers to the `#register` element
    $(this).find('.registerSubmitter').on('click', function(e) {
        // do something
    });
});
  • Bind the delegated event handlers once and don't worry about when pages are actually in the DOM:

.

//this can be run in the global scope
$(document).on('click.register', '.registerSubmitter', function(e) {
    // do something
});

Basically when you bind an event using delegation like you are, the actual CPU hit of adding the event handler is less but each time an event is dispatched (of any kind that bubbles) it has to be checked if it matches the delegated event handler's selector.

When you bind directly to elements it generally takes more time to do the actual binding because each individual element has to be bound to rather than binding once to the document element like with event delegation. This however has the benefit that no code runs unless a specific element receives a specific event.

A quick blurb from the documentation:

Triggered on the page being initialized, after initialization occurs. We recommend binding to this event instead of DOM ready() because this will work regardless of whether the page is loaded directly or if the content is pulled into another page as part of the Ajax navigation system.

Source: http://jquerymobile.com/demos/1.1.0/docs/api/events.html