您是否曾经遇到过在JavaScript中查找DOM节点的父节点问题,但不确定要遍历多少层才能找到它?让我们来看看这个HTML:
<div data-id="123">
<button>Click me</button>
</div>
假设您想在用户单击按钮后获取data-id的值:
var button = document.querySelector("button");
button.addEventListener("click", (evt) => {
console.log(evt.target.parentNode.dataset.id);
// prints "123"
});
在这种情况下Node.parentNode的API就足够了,它的作用是返回给定元素的父节点。
但是如果HTML结构的嵌套深度超过这个值呢?难道要element.parentNode.parentNode.parentNode.dataset.id
老方法:使用while循环
利用while循环,直到找到父节点为止。
function getParentNode(el, tagName) {
while (el && el.parentNode) {
el = el.parentNode;
if (el && el.tagName == tagName.toUpperCase()) {
return el;
}
}
return null;
}
再次使用上面的同一个HTML示例,如下所示:
var button = document.querySelector("button");
console.log(getParentNode(button, 'div').dataset.id);
// prints "123"
这个办法并非完美。想象一下,如果您想使用id或className或任何其他类型的选择器,而不是标签名。但至少它允许父节点和源节点之间有可变数量的子节点。
新方法:使用Element.closest()
var button = document.querySelector("button");
console.log(button.closest("div"));
// prints the HTMLDivElement
Element.closest()允许我们向上遍历DOM,直到得到与给定选择器匹配的元素。我们可以传递任何选择器Element.querySelector或者Element.querySelectorAll. 它可以是一个ID、class类名、data数据属性、标签等。
element.closest("#my-id"); // yep
element.closest(".some-class"); // yep
element.closest("[data-id]:not(article)") // hell yeah
Element.closest() 方法用来获取:匹配特定选择器且离当前元素最近的祖先元素(也可以是当前元素本身)。如果匹配不到,则返回 null。
var button = document.querySelector("button");
console.log(button.closest(".i-am-in-the-dom"));
// prints HTMLElement
console.log(button.closest(".i-am-not-here"));
// prints null
if (button.closest(".i-am-in-the-dom")) {
console.log("Hello there!");
} else {
console.log(":(");
}
Element.closest()兼容polyfill方案查看这里。