jQuery.closest() 实现的 DOM/纯 JavaScript 解决方案?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22100853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DOM / pure JavaScript solution to jQuery.closest() implementation?
提问by chrisjlee
Here's the markup i'm trying to query. So given the markup:
这是我要查询的标记。所以给定标记:
<table class="non-unique-identifier table">
<tr><td><div id="unique-identifier"></div></td></tr>
</table>
I'm querying for #unique-identifier:
我正在查询#unique-identifier:
var myDiv = document.getElementById('#unique-identifier');
I'm then trying to select the table. The issue is that i want to make the code not brittle so i don't need to do this:
然后我试图选择表格。问题是我想让代码不脆弱,所以我不需要这样做:
var myDiv = document.getElementById('#unique-identifier'),
myTable = myDiv.parentNode.parentNode.parentNode.parentNode;
My question
我的问题
Is there currently a DOM implementation of the jQuery equivalent of $().closest() ? A closest implementation that is efficient without nested for loops would be preferred.
当前是否有等效于 $().closest() 的 jQuery 的 DOM 实现?没有嵌套 for 循环的最接近的实现将是首选。
Limitations
限制
I'm required to not use jQuery or sizzle for this particular issue or introduce any new libraries. The code is quite old as well. Thus, that is the reason for such limitations and the existence of <tables>
.
我被要求不要针对这个特定问题使用 jQuery 或 sizzle 或引入任何新库。代码也很旧。因此,这就是这种限制和存在的原因<tables>
。
回答by leaf
You can't do this without a loop :
没有循环你不能这样做:
function closest (el, predicate) {
do if (predicate(el)) return el;
while (el = el && el.parentNode);
}
Well, actually you can, using recursivity (a disguised loop) :
嗯,实际上你可以,使用递归(一个伪装的循环):
function closest(el, predicate) {
return predicate(el) ? el : (
el && closest(el.parentNode, predicate)
);
}
A demo (using Sizzlefor the DOM queries) :
演示(使用Sizzle进行 DOM 查询):
// s = selectors
// n = number of selectors
// get closest s[i+1] from s[i]
// where 0 <= i < n and i % 2 = 0
function main (s) {
var i, el, from;
var n = s.length;
for (i = 0; i < n; i += 2) {
from = Sizzle(s[i])[0];
el = closest(from, function (el) {
return !!el && el !== document && (
Sizzle.matchesSelector(el, s[i + 1])
);
});
console.log(el);
}
}
function closest (el, predicate) {
do if (predicate(el)) return el;
while (el = el && el.parentNode);
}
main([
"#winner" , "b",
"#winner" , "p",
"#winner" , "div",
"#winner" , "div:not(#trump)",
"#winner" , "#clinton",
"#looser" , "html"
]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/sizzle/1.10.18/sizzle.min.js"></script>
<div id="main">
<div id="trump">
<p>Donald <b id="winner">Trump</b></p>
</div>
<div id="clinton">
<p>Hillary <b>Clinton</b></p>
</div>
</div>
回答by Michael S
To add an updated answer, there is now Element.closest(<query_selector>)
available.
要添加更新的答案,现在Element.closest(<query_selector>)
可用。
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
This isn't supported on IE, but that mozilla doc page includes code for a polyfill for IE8 and IE9+.
这在 IE 上不受支持,但该 mozilla 文档页面包含用于 IE8 和 IE9+ 的 polyfill 的代码。
回答by antitoxic
Concise and quick (tested with Benchmark.js) way to search for closest element by any css selector:
通过任何 css 选择器搜索最接近元素的简洁快速(使用 Benchmark.js 测试)方法:
var ep = Element.prototype;
ep.matches = ep.matches || ep.webkitMatchesSelector || ep.msMatchesSelector || ep.mozMatchesSelector;
function getClosest( elem, selector ) {
while (elem !== document.body) {
elem = elem.parentElement;
if (elem.matches(selector)) return elem;
}
}
Supports IE9+ and the rest of the browsers you can expect to care about.
支持 IE9+ 和其他您可能关心的浏览器。
回答by fboes
function closestById(el, id) {
while (el.id != id) {
el = el.parentNode;
if (!el) {
return null;
}
}
return el;
}
// Use it like:
yourTarget = closestById(document.getElementById('unique-identifier'),'targetId')
alert(yourTarget.id);
<div id="targetId">
Finish
<div>
<div id="unique-identifier">
Start
</div>
</div>
</div>
This searches upwards, until a certain ID is found. You can also alter the code to find certain classes.
这将向上搜索,直到找到某个 ID。您还可以更改代码以查找某些类。
回答by MasNotsram
Alternative is a recursive function. This is slightly different to closest as i searches the children, I'm not sure if closest does.
另一种是递归函数。当我搜索孩子时,这与最接近的略有不同,我不确定是否最接近。
function closest(elem) {
if( elem.className.indexOf("non-unique-identifier") ) {
return elem;
}
var parent = elem.parentNode;
for(var i = 0; i< parent.children.length; i++ ) {
if( parent.children[i].className.indexOf("non-unique-identifier")!=-1) {
return parent.children[i];
}
}
return closest(parent);
}
var elem = document.getElementById('unique-identifier');
var cl = closest(elem);
console.log(cl);
Non children searching example (more like closest):
非儿童搜索示例(更像是最接近的):
function closest(elem) {
if( elem.className.indexOf("non-unique-identifier") ) {
return elem;
}
var parent = elem.parentNode;
if( parent.className.indexOf("non-unique-identifier")!=-1) {
return parent;
}
return closest(parent);
}
var elem = document.getElementById('unique-identifier');
var cl = closest(elem);
console.log(cl);
回答by Uday Hiwarale
<div class="item">
<div class="itemed">
<p>Hello <b class="itemed" id="world">World</b></p>
</div>
</div>
function closest(el, classname) {
if(el.parentNode){
if(el.parentNode.className.includes(classname)){
return el.parentNode;
}
else{
return closest(el.parentNode, classname);
}
}
else{
return false;
}
}
var world = document.getElementById('world');
var closest = closest(world, 'item');
console.log(closest);
回答by Arkadiusz Miszczyszyn
I wrote this simple function in one of my TypeScript projects so i used querySelector on parentNode so you can pass to function class
, id
, tag name
etc
我在打字稿项目之一写了这个简单的功能,所以我用querySelector上parentNode,所以你可以传递给函数class
,id
,tag name
等
findParentNode(el, selector:string):Element | null {
let found = null;
let child = el;
let childSelector = guessSelector(child);
while(child !== document && found === null) {
child = child.parentNode;
childSelector = guessSelector(child);
found = childSelector ? child.parentNode.querySelector(`${childSelector} > ${selector}`) : null;
}
return found;
function guessSelector(child:any):string {
childSelector = child.className ? `.${child.className.replace(' ', '.')}` : null;
if (typeof child.getAttribute === 'function') {
childSelector = !childSelector ?
(child.getAttribute('id') ? `#${child.getAttribute('id')}` : null) : childSelector;
childSelector = !childSelector ?
child.tagName.toLowerCase() : childSelector;
}
return childSelector;
}
}
Example:
例子:
If you want to find closest parent of target
which has .param-input
class you can do this like this:
如果你想找到最接近的父母target
拥有.param-input
类,你可以做到这一点是这样的:
document.body.addEventListener('click', (e) => {
console.log(findParentNode(e.target, '.param-input'));
});
回答by Jo?o Henrique Barbosa
In this case, use JavaScript's closest()
在这种情况下,使用 JavaScript 的最接近 ()
Exemple:
例子:
var el = document.getElementById('div-03');
var r1 = el.closest("#div-02");
// returns the element with the id=div-02
var r2 = el.closest("div div");
// returns the closest ancestor which is a div in div, here is div-03 itself
var r3 = el.closest("article > div");
// returns the closest ancestor which is a div and has a parent article, here is div-01
var r4 = el.closest(":not(div)");
// returns the closest ancestor which is not a div, here is the outmost article
<article>
<div id="div-01">Here is div-01
<div id="div-02">Here is div-02
<div id="div-03">Here is div-03</div>
</div>
</div>
</article>
You can find more information, on MDN Web Docs by clicking here
您可以通过单击此处在 MDN Web Docs 上找到更多信息