另一种方法
你的目标
根据您在原问题中的评论,您的总体目标是:
有一个博客列表。每个博客都有像“编辑”和“删除”之类的按钮。当我点击这些按钮时,我想找到它的博客元素。
我认为解决您面临的问题的最佳方法(而不是回答您提出的问题-抱歉!)是以不同的方式来解决问题。
从您的评论中,您说您有类似以下内容:
<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>
你的目标是为每个 blog-link
项的 button
元素添加 click
事件处理程序。
因此,让我们将该目标从普通英语翻译成伪代码:
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问题/答案,了解有关闭包的更多信息:
JavaScript闭包如何工作?
我们添加HTMLCollection.prototype.forEach...行,为所有HTMLCollection对象提供forEach功能。像getElementsByClassName这样的函数返回一个HTMLCollection对象。它在大多数情况下像一个数组一样运作,但默认情况下不允许我们使用forEach。关于兼容性的说明:您可以使用标准的for循环,因为forEach在所有浏览器中都不可用(主要是旧版IE浏览器的问题)。我更喜欢使用forEach的习惯用法。
最终结果
最终结果是代码稍微长一些,因为问题的范围比您实际提出的问题要广泛一些。优点是此代码更加灵活,抵抗HTML结构变化的能力更强。
.closest()
方法(纯 JavaScript),它的工作方式类似于 jQuery 的.closest()
方法。 - Josh Crozier