API DOM Events: делегирование событий и stopPropagation
Это код с JQuery 1.7:
<div class="test">
<div class="bu">
<a>
bu here
</a>
</div>
</div>
<script src="http://code.jquery.com/jquery-1.7.js"></script>
<script>
$(document).on('click', '.test', function () { alert(0); return false; });
$(document).on('click', '.bu', function () { alert(1); return false; });
$(document).on('click', '.bu', function () { alert(2); return false; });
</script>
Нажатие на .test>.bu предупредит "1" и предупредит "2", но не предупредит "0"
Мой вопрос: как сделать то же самое БЕЗ jQuery (на нативном DOM API)? Кажется, я не могу сделать это с Native DOM API, не реализовав свою собственную библиотеку...
Ответы
Ответ 1
<div class="a">
<div class="b">
<div class="c" style="border: 1px solid silver; width: 80px; text-align: center;line-height: 80px;">
click me!
</div>
</div>
</div>
<script>
// Element.prototype.matchesSelector
(function (x) {
var i;
if (!x.matchesSelector) {
for (i in x) {
if (/^\S+MatchesSelector$/.test(i)) {
x.matchesSelector = x[i];
break;
}
}
}
}(Element.prototype));
Document.prototype.on =
Element.prototype.on = function (eventType, selector, handler) {
this.addEventListener(eventType, function listener(event) {
var t = event.target,
type = event.type,
x = [];
if (event.detail && event.detail.selector === selector && event.detail.handler === handler) {
return this.removeEventListener(type, listener, true);
}
while (t) {
if (t.matchesSelector && t.matchesSelector(selector)) {
t.addEventListener(type, handler, false);
x.push(t);
}
t = t.parentNode;
}
setTimeout(function () {
var i = x.length - 1;
while (i >= 0) {
x[i].removeEventListener(type, handler, false);
i -= 1;
}
}, 0);
}, true);
};
Document.prototype.off =
Element.prototype.off = function (eventType, selector, handler) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent(eventType, false, false, {selector: selector, handler: handler});
this.dispatchEvent(event);
};
document.on('click', '.b', function () {
alert(2);
});
document.on('click', '.a', function () {
alert(1);
});
document.on('click', '.b', function (event) {
alert(3);
event.stopPropagation();
});
</script>
Ответ 2
Здесь вы идете:
document.addEventListener( 'click', function ( e ) {
if ( hasClass( e.target, 'bu' ) ) {
// .bu clicked
// do your thing
} else if ( hasClass( e.target, 'test' ) ) {
// .test clicked
// do your other thing
}
}, false );
где hasClass
-
function hasClass( elem, className ) {
return elem.className.split( ' ' ).indexOf( className ) > -1;
}
Live demo: http://jsfiddle.net/Nrxp5/30/
Ответ 3
Вот версия на основе прототипа
Document.prototype.on = function(event, target = null, callBack){
this.addEventListener(event, function(event){
let len = target.length, i = 0;
while(i < len){
if(event.target === target[i]){
callBack.call(target[i], event);
}
i ++;
}
}, false);
};
Использование такое же, как у jQuery:
let btns = document.getElementsByTagName('button');
document.on('click', btns, function(event){
console.log(this.innerText)
});
И живой пример ниже:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body bgcolor="#000">
<button>hello1</button>
<button>hello2</button>
<script type="text/javascript">
Document.prototype.on = function(event, target = null, callBack = function(){}){
this.addEventListener(event, function(event){
let len = target.length, i = 0;
while(i < len){
if(event.target === target[i]){
callBack.call(target[i], event);
}
i ++;
}
}, false);
};
//example of usage
let btns = document.getElementsByTagName('button');
document.on('click', btns, function(t){
alert(this.innerText);
})
//add elements after delegating an event
let newBtn = document.createElement('button');
newBtn.innerText = 'btnNew';
document.body.appendChild(newBtn);
//delay to create
setTimeout(function(){
let newBtn = document.createElement('button');
newBtn.innerText = 'another btnNew';
document.body.appendChild(newBtn);
},2000);
</script>
</body>
</html>