1

I know that jquery or zepto $(selctor).on(event, handler) will trigger events of dynamic created elements. But I don't use jquery and zepto.I'd like write my code from scratch for both learning and lightweigh.

There are lots of sth.innerHTML=blabla and sth.appendChild(..) snippets in my codes. I have to bind event to them.

Update:

I want a simple function like this,

function $on(selector, eventType, handler) {
    document.querySelectAll(selector).forEach(function(el) {
        el.addEventListener(eventType, handler);
    });
    // on new DOM insert or replaced, let us call it newDom
      newDom.querySelectAll(selector).forEach(function(el) {
          el.addEventListener(eventType, handler);
      });
}

but I don't know if jquery work like this, I want to know it, and complete my function.

Community
  • 1
  • 1
guilin 桂林
  • 17,050
  • 29
  • 92
  • 146
  • What about event propagation? This way you don't have to deal with the overhead of binding and unbinding on each element you push in or remove from the dom? – Newse Feb 18 '14 at 03:52
  • @Newse, it's unmistakable that jQuery and zepto make some things easier, but it's certainly worthwhile to want to know how to do some things on your own. – Mulan Feb 18 '14 at 04:14
  • Just for a reference, jQuery has decided to deprecate the [`live()`](http://api.jquery.com/live/) method, if your *dynamic* is creating elements after the event binding. – Arie Xiao Feb 18 '14 at 04:14
  • @naomik - you are absolutely correct, but what does event propagation have to do with jquery or zepto. The reason I suggested this technique is because it would mitigate the overhead of adding an event handler to every element that would be added dynamically. http://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing – Newse Feb 18 '14 at 04:27
  • This guys has written some pure js code that's equal to JQuery http://stackoverflow.com/questions/14237233/jquery-functions-equivalent-in-pure-javascript – Mohammed Joraid Feb 18 '14 at 05:12
  • @guilin桂林 I've made some edits to my answer below. I hope this gets you on the right track. – Mulan Feb 18 '14 at 19:18

1 Answers1

5

Here's an example using the newer MutationObserver recommended by the MDN docs.

This depends on Element.prototype.matches which is not widely supported yet. However, I created a little wrapper to make it easier to work with.

DEMO

// live listener function
(function(window) {

  // Element.matches "polyfill"
  (function(e){
    if (typeof e.matches !== "function") {
      e.matches = e.webkitMatchesSelector ||
                  e.mozMatchesSelector    ||
                  e.msMatchesSelector     ||
                  e.oMatchesSelector      ||
                  e.matchesSelector;
    }
  })(Element.prototype);

  function on(selector, eventType, handler) {
    // add listener for all existing elements
    [].forEach.call(document.querySelectorAll(selector), function(elem) {
      elem.addEventListener(eventType, handler);
    });

    // create new "live" observer
    var observer = new MutationObserver(function(records) {
      records.forEach(function(record) {
        [].forEach.call(record.addedNodes || [], function(elem) {
          if (elem.matches(selector)) {
            elem.addEventListener(eventType, handler);
          }
        });
      });
    });

    // watch for DOM changes to body's children and body's subtree
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });

    return observer;
  }

  window.on = on;
})(window);

Let's create some elements

// sample button generator
function createButton() {
  var b = document.createElement("button");
  b.className = "hello";
  b.innerHTML = "Spaghett";
  document.body.appendChild(b);
}

// create a new button every second
setInterval(createButton, 1000);

Actual usage

on("button.hello", "click", function(event) {
  alert("spooked ya!");
  event.preventDefault();
});

Notable notes!

I'm using [].forEach.call(..., fn) because querySelectorAll does not return an Array. Instead, it returns a NodeList. A NodeList object does not have Array.prototype in its prototype chain and therefore does not have direct access to the .forEach function. MutationRecord.prototype.addedNodes also returns a NodeList.

Mulan
  • 129,518
  • 31
  • 228
  • 259