问题
I would emulate in pure javascript the main functionality of jQuery .on( events , selector , data) method.
For example
$(document).on('click','.button',function() {
console.log("jquery onclick");
});
I thought it was enough make something like this
document.addEventListener('click',function(e) {
if(e.target.className == 'button2') {
console.log("It works");
}
});
However when I have this html structure:
<button class="button2">Hello <span>World</span></button>
my script doesn't works when the click event is triggered on span
element, because e.target
is span
. (I ignore for this question the complexity of elements with multiple class, and crossbrowsers compatibility)
The source of jQuery is not simple to read and I don't understand how it works (because the first piece of code, in jQuery, works with my html structure).
I need this method because my html is dynamic, and buttons with this class are created, deleted and re-created many times. I don't want add listeners every times.
I would avoid, if possible, to include jquery library.
So, I can do this?
Here the jsFiddle for testing.
回答1:
This is actually surprisingly simple. You're on the right track, but it's not quite there.
Here's the functions I use:
window.addEvent = function(elem,type,callback) {
var evt = function(e) {
e = e || window.event;
return callback.call(elem,e);
}, cb = function(e) {return evt(e);};
if( elem.addEventListener) {
elem.addEventListener(type,cb,false);
}
else if( elem.attachEvent) {
elem.attachEvent("on"+type,cb);
}
return elem;
};
window.findParent = function(child,filter,root) {
do {
if( filter(child)) return child;
if( root && child == root) return false;
} while(child = child.parentNode);
return false;
};
window.hasClass = function(elem,cls) {
if( !('className' in elem)) return;
return !!elem.className.match(new RegExp("\\b"+cls+"\\b"));
};
The window.findParent
is central to the whole thing, as you can see when I show you how to attach your desired on
listener:
window.addEvent(document.body,"click",function(e) {
var s = window.findParent(e.srcElement || e.target,function(elm) {
return window.hasClass(elm,"button");
},this);
if( s) {
console.log("It works!");
}
});
回答2:
Update for 2017: current DOM standards like closest mean this is now much easier.
const addEventForChild = function(parent, eventName, childSelector, cb){
parent.addEventListener(eventName, function(event){
const clickedElement = event.target,
matchingChild = clickedElement.closest(childSelector)
if (matchingChild) cb(matchingChild)
})
};
To use it just:
addEventForChild(parent, 'click', '.child', function(childElement){
console.log('Woo click!', childElement)
})
Here's a jsfiddle
回答3:
Easy and short code:
function onEvt(type, callback) {
if (document.attachEvent) {
document.attachEvent("on" + type, function (e) {
callback(e.target);
});
} else {
document.addEventListener(type, function (e) {
callback(e.target);
}, false);
}
}
Call the function like this:
onEvt('click', function(elem){ // click, mouseover etc...
// for class
if(elem.classList.contains('classname')){
// do stuff
}
// for attribute
if(elem.hasAttribute('target')){
// do stuff
}
});
来源:https://stackoverflow.com/questions/14677019/emulate-jquery-on-with-selector-in-pure-javascript