JavaScript события и пузыри
У меня есть следующий (упрощенный) код разметки:
<div id="container">
<div data-value="1">
<span>Click me 1</span>
</div>
<div data-value="2">
<span>Click me 2</span>
</div>
</div>
<div id="messages"></div>
Я хочу воспользоваться всплеском, подключив прослушиватель событий только на #container
, и получить кликнул детский data-value
,
document.getElementById('container').addEventListener('click', function(e){
document.getElementById('messages').innerHTML = 'you clicked ' + e.target.dataset.value;
}, false);
Все работает нормально, если область нажатия div
площадь (красным на скрипке). Как я могу получить data-value
также, когда щелчок происходит от дочерних элементов div (например, щелчок по синему промежутку) со значением данных без изменения прослушивателя событий?
Вот скрипка: http://jsfiddle.net/hgLagy31/1/
3 ответа
e.target
элемент, по которому щелкнул пользователь, показывает undefined
так как <span>
не имеет data-value
приписывать. Вы можете подняться на дерево и найти ближайшего предка, который содержит data-value
,
document.getElementById('container').addEventListener('click', function(e) {
// Find nearest ancestor with data-value defined
var node = e.target;
while (!node.dataset.value) {
node = node.parentNode;
}
document.getElementById('messages').innerHTML =
'you clicked ' + node.dataset.value;
}, false);
#container > div {
background: red;
}
#container > div > span {
background: blue;
color: white;
}
<div id="container">
<div data-value="1">
<span>Click me 1</span>
</div>
<div data-value="2">
<span>Click me 2</span>
</div>
</div>
<div id="messages"></div>
Чтобы сделать это более надежным, вы можете проверить, node
является undefined
прежде чем продолжить в while
цикл и выход, если так:
while (!node.dataset || !node.dataset.value) {
node = node.parentNode;
if (!node) {
document.getElementById('messages').innerHTML =
'Could not find data-value';
return;
}
}
document.getElementById('container').addEventListener('click', function(e) {
// Find nearest ancestor with data-value defined
var node = e.target;
while (!node.dataset || !node.dataset.value) {
node = node.parentNode;
if (!node) {
document.getElementById('messages').innerHTML = 'Could not find data-value';
return;
}
}
document.getElementById('messages').innerHTML =
'you clicked ' + node.dataset.value;
}, false);
#container > div {
background: red;
}
#container > div > span {
background: blue;
color: white;
}
<div id="container">
<div data-value="1">
<span>Click me 1</span>
</div>
<div data-value="2">
<span>Click me 2</span>
</div>
<div>
<span>Click me 3</span>
</div>
</div>
<div id="messages"></div>
Как уже упоминалось, получить целевой элемент, а затем пройти через .parentNode
Не все браузеры поддерживают target/toElement, поэтому я использую следующий polyfill при получении целевого элемента:
var target = e.toElement || e.relatedTarget || e.target || function () { throw "Failed to attach an event target!"; }
Где е это событие
Как вы просили решение, которое не включает в себя изменение слушателя событий...
#container > div > span {
background: blue;
color: white;
pointer-events: none;
}
Это позволит событию click всплыть прямо в контейнер.