Ответ 1
Альтернативный подход
Ваша цель
Согласно вашим комментариям по оригинальному вопросу, ваша общая цель такова:
Существует список блога. В каждом блоге есть кнопка, например "редактировать" и "удалять". Когда я нажимаю такие кнопки, я хочу найти элемент блога.
Я считаю, что лучший подход к решению проблемы, с которой вы столкнулись (в отличие от ответа на заданный вами вопрос - извините!), заключается в том, чтобы подойти к проблеме по-другому.
Из ваших комментариев вы сказали, что у вас есть что-то вроде этого:
<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`);
Пример script
Рабочий пример: http://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
принадлежит.
Ознакомьтесь с этим вопросом/ответом о закрытии для получения дополнительной информации: Как работают блокировки JavaScript?
И мы добавляем строку HTMLCollection.prototype.forEach...
, чтобы обеспечить функциональность forEach
всем объектам HTMLCollection
. Такие функции, как getElementsByClassName
, возвращают объект HTMLCollection
. Он действует как массив по большей части, но по умолчанию он не позволяет нам использовать forEach
. Заметка о совместимости: вы можете использовать стандартный цикл for
, поскольку forEach
недоступен во всех браузерах (в основном виноваты старые браузеры IE). Я предпочитаю идиому forEach
.
Конечный результат
Конечный результат - это немного более длинный код, поскольку объем проблемы немного шире, чем вопрос, который вы действительно задали. Преимущество в том, что этот код гораздо более гибкий и устойчивый к нарушению изменений в структуре HTML.