另一种方法
你的目标
根据您对原始问题的 cmets,您的总体目标是:
有一个博客列表。每个博客都有一个按钮,如“编辑”和“删除”。当我点击这些按钮时,我想找到它的博客元素。
我相信解决您面临的问题的最佳方法(而不是回答您提出的问题 - 抱歉!)是以不同的方式解决问题。
从你的 cmets 中,你说你有这样的东西:
<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 事件处理程序添加到每个blog-link 项目的button 元素。
所以让我们把这个目标从简单的英语翻译成伪代码:
for each `blog-link` `b`
delete_button.onclick = delete_handler(`b`);
edit_button.onclick = edit_handler(`b`);
示例脚本
工作示例: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 结构如何变化,只要类和 ID 保持一致,我们的 JavaScript 就不会中断。
此解决方案遍历 #blog-list 元素中的每个 blog-item:
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 问题/答案以获取更多信息:How do JavaScript closures work?
我们加入HTMLCollection.prototype.forEach... 行,为所有HTMLCollection 对象提供forEach 功能。像getElementsByClassName 这样的函数返回一个HTMLCollection 对象。它在很大程度上与数组完全一样,但默认情况下它不允许我们使用forEach。关于兼容性的说明:您当然可以使用标准的 for 循环,因为 forEach 并非在所有浏览器中都可用(主要是旧的 IE 浏览器是罪魁祸首)。我更喜欢forEach 成语。
最终结果
最终结果是代码有点长,因为问题的范围比您实际提出的问题要宽一些。优点是这段代码更加灵活,并且不会被 HTML 结构的更改破坏。