Альтернативный подход
Ваша цель
Согласно вашим комментариям к исходному вопросу, ваша общая цель такова:
Есть список блогов. В каждом блоге есть кнопки типа "редактировать" и "удалить". Когда я нажимаю такие кнопки, я хочу найти элемент блога.
Я считаю, что лучший подход к решению проблемы, с которой вы столкнулись (в отличие от ответа на вопрос, который вы задали - извините!) - это подойти к проблеме по-другому.
Из ваших комментариев вы сказали, что у вас есть что-то вроде этого:
<ul id="blog-list">
<li class="blog-item">
<a href="blog1.com">
Boats galore!
</a>
<span class="blog-description">
This is a blog about some of the best boats from Instagram.
</span>
<span class="blog-button delete-button">
Delete
</span>
<span class="blog-button edit-button">
Edit
</span>
</li>
<li class="blog-item">
<a href="blog2.com">
Goats galore!
</a>
<span class="blog-description">
A blog about the everyday adventures of goats in South Africa.
</span>
<span class="blog-button delete-button">
Delete
</span>
<span class="blog-button edit-button">
Edit
</span>
</li>
<li class="blog-item">
<a class="blog-link" href="blog3.com">
Totes galore!
</a>
<span class="blog-description">
A blog about containers and bags, and the owners who love them.
</span>
<span class="blog-button delete-button">
Delete
</span>
<span class="blog-button edit-button">
Edit
</span>
</li>
</ul>
И ваша цель — добавить click
обработчиков событий к button
элементам для каждого blog-link
элемента.
Итак, давайте просто переведем эту цель с простого английского на псевдокод:
for each `blog-link` `b`
delete_button.onclick = delete_handler(`b`);
edit_button.onclick = edit_handler(`b`);
Пример скрипта
Рабочий пример: https://jsfiddle.net/vbt6bjwy/10/.
<script>
function deleteClickHandler(event, parent) {
event.stopPropagation();
parent.remove();
}
function editClickHandler(event, parent) {
event.stopPropagation();
var description = parent.getElementsByClassName("blog-description")[0];
description.innerHTML = prompt("Enter a new description:");
}
function addClickHandlers() {
var bloglistElement = document.getElementById("blog-list");
var blogitems = bloglistElement.getElementsByClassName("blog-item");
blogitems.forEach(function(blogitem){
var deleteButtons = blogitem.getElementsByClassName("delete-button");
deleteButtons.forEach(function(deleteButton){
deleteButton.onclick = function(event) {
return deleteClickHandler(event, blogitem);
}
});
var editButtons = blogitem.getElementsByClassName("edit-button");
editButtons.forEach(function(editButton){
editButton.onclick = function(event) {
return editClickHandler(event, blogitem);
}
});
});
}
HTMLCollection.prototype.forEach = Array.prototype.forEach;
addClickHandlers();
</script>
Объяснение
Способ, который вы выбрали для реализации решения, действителен, но я подумал, что дам вам другой взгляд на ту же проблему.
На мой взгляд, внутренние теги сущности blog
не должны знать структуру или свойства окружающего HTML, чтобы ваши кнопки edit
и delete
работали.
Ваше исходное решение должно работать в обратном направлении от каждого button
вверх по цепочке родительских элементов, пока не найдет то, что, по его предположению, является правильным родительским элементом, основанным на хрупком методе, таком как жесткое кодирование, перемещающееся вверх N
раз в цепочке родительских элементов. Разве не было бы лучше, если бы мы могли использовать обычный выбор элементов JavaScript, чтобы быть абсолютно уверенными в том, что мы выбираем? Таким образом, независимо от того, как может измениться структура HTML, наш JavaScript не сломается, пока классы и идентификаторы остаются согласованными.
Это решение перебирает каждый blog-item
в элементе #blog-list
:
blogitems.forEach(function(blogitem){ ... });
В цикле forEach
мы захватываем массивы, содержащие элементы .delete-button
и .edit-button
. Для каждого из этих элементов мы добавляем соответствующий обработчик событий в свойство onclick
:
deleteButtons.forEach(function(deleteButton){
deleteButton.onclick = function(event) {
return deleteClickHandler(event, blogitem);
}
});
Для каждого элемента deleteButton в массиве мы назначаем анонимную функцию обработчику событий onclick
. Создание этой анонимной функции позволяет нам создать замыкание.
Это означает, что каждая функция deleteButton.onclick
будет индивидуально «запоминать», к какому blogitem
она принадлежит.
Ознакомьтесь с этим вопросом/ответом SO о замыканиях для получения дополнительной информации: Как работают замыкания JavaScript?
И мы добавляем строку HTMLCollection.prototype.forEach...
, чтобы обеспечить функциональность forEach
для всех HTMLCollection
объектов. Такие функции, как getElementsByClassName
, возвращают объект HTMLCollection
. По большей части он действует точно так же, как массив, но не позволяет нам использовать forEach
по умолчанию. Примечание о совместимости: вы, безусловно, можете использовать стандартный цикл for
, так как forEach
доступен не во всех браузерах (в основном виноваты старые браузеры IE). Я предпочитаю идиому forEach
.
Конечный результат
Конечным результатом является немного более длинный код, поскольку масштаб проблемы немного шире, чем вопрос, который вы на самом деле задали. Преимущество заключается в том, что этот код гораздо более гибкий и устойчивый к нарушениям при изменении структуры HTML.
02.02.2016