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.