JavaScript event binding module.
-
Support legacy browsers
-
Bind events to any objects
-
Bind DOM events and custom events with the same interface
-
Event delegation
-
Modularized JS programming pattern
-
JSHint code quality
// Dom events
zxEvents.addEvent(element, "click", logThis);
zxEvents.addEvent(removeEventLink, "click", function() {
zxEvents.remnoveEvent(element, "click", logThis);
});
// Custom events
zxEvents.addEvent(testObject, "customEvent", logThis);
zxEvents.addEvent(testObject, "customEvent", logValue);
zxEvents.triggerEvent(testObject, "customEvent", [1]);
zxEvents.triggerEvent(testObject, "customEvent", [1], testObject);
// Event delegation
zxEvents.delegateEvent(document.getElementsByTagName("body")[0], "click", logThis, "#test-delegate-target");
Event binding is never easy.
There are several features that could be considered to support in an event binding module:
-
Cross bowser event binding
-
Event delegation
-
Custom events
-
Event listening
-
Mimic events bubbling
Cross browser maybe the lowest hanging fruit. Support for custom binding and mimic events bubbling for event delegation could be very tricky.
Generally, we are there are two kinds of events about event binding:
-
DOM events like 'click', 'keydown'. They are bound to element objects, triggered by browser, and have event bubbling or capturing.
-
Custom events. They can be bound to any object. You could use a subscriber pattern to support event listening.
Most libraries or technics do not support DOM events and custom events at the same time:
-
Gator.js only deal with DOM events.
-
Backbone.Events only support custom bindings actuarially, it delegate DOM event bindings to other libraries like jQuery or Zepto.
What zxEvents trying to do is to support DOM events and custom events in the same interface.
This is the addEvent function in zxEvents:
var addEvent = function(obj, type, fn) {
var events;
var useCapture;
// For Microsoft
// If not DOM event, attach callback to obj as custom events of any object
if (obj.attachEvent && domEvents['on'+type]) {
obj['e'+ type + fn] = fn;
// Use an anonymous function to fix 'this' reference in IE
obj[type + fn] = function() {
// So 'this' points to obj
obj['e'+type+fn](window.event);
}
obj.attachEvent('on'+ type, obj[type + fn]);
}
// For W3C
else if (obj.addEventListener) {
// For event delegation
// Blur and focus do not bubble up, so we need to use event capturing
useCapture = (type == 'blur'|| type == 'focus');
obj.addEventListener(type, fn, useCapture);
}
// For custom events of any object
else {
obj.events || (obj.events = {});
events = obj.events[type] || (obj.events[type] = []);
events.push(fn);
}
};
With this function, you can bind to any object DOM events or customs, in the same interface. Other detail explanations could be found in comment of source code.
It just bind them as mouseover and mouseout. That's not a good implementation.
Gator.addEvent=function(gator,type,callback){
if(gator.element.addEventListener){
returnoldAddEvent(gator,type,callback);
}
// internet explorer does not support event capturing
// but does have fallback events to use that will bubble
if(type=='focus'){
type='focusin';
}
if(type=='blur'){
type='focusout';
}
gator.element.attachEvent('on'+type,callback);
};
jQuery create a fix function, and do event-time checks.
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
delegateType: fix,
bindType: fix,
handle: function( event ) {
var ret,
target = this,
related = event.relatedTarget,
handleObj = event.handleObj;
// For mousenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
event.type = handleObj.origType;
ret = handleObj.handler.apply( this, arguments );
event.type = fix;
}
return ret;
}
};
});
Gators.js use a stack to record elements that matches the selector from the event target all the way up to the bound element(or the root element). Then the callbacks in stack will be invoked level by level, if any of these callbacks returned false or stopped event bubbling, the process will return.
for (selector in _handlers[id][type]) {
if (_handlers[id][type].hasOwnProperty(selector)) {
match = _matchesSelector(target, selector, _gator_instances[id].element);
if (match && Gator.matchesEvent(type, _gator_instances[id].element, match, selector == '_root', e)) {
_level++;
_handlers[id][type][selector].match = match;
matches[_level] = _handlers[id][type][selector];
}
}
}
// stopPropagation() fails to set cancelBubble to true in Webkit
// @see http://code.google.com/p/chromium/issues/detail?id=162270
e.stopPropagation = function () {
e.cancelBubble = true;
};
for (i = 0; i <= _level; i++) {
if (matches[i]) {
for (j = 0; j < matches[i].length; j++) {
if (matches[i][j].call(matches[i].match, e) === false) {
Gator.cancel(e);
return;
}
if (e.cancelBubble) {
return;
}
}
}
}
Backbone.js source code
http://backbonejs.org/#Events-on
Gator.js source code
https://github.com/ccampbell/gator
Dean Edward’s blog
http://dean.edwards.name/weblog/2005/10/add-event/
http://therealcrisp.xs4all.nl/upload/addEvent_dean.html#
John Resig’s blog
http://ejohn.org/projects/flexible-javascript-events/
Event binding Contest
http://www.quirksmode.org/blog/archives/2005/09/addevent_recodi.html
Events models
http://www.quirksmode.org/js/events_advanced.html
Support events
http://www.quirksmode.org/dom/events/index.html
Delegating
Custom events
http://stackoverflow.com/questions/5342917/custom-events-in-ie-without-using-libraries
jQuery source code