Here\'s the markup i\'m trying to query. So given the markup:
相关标签:
8条回答
2020-12-06 00:51
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
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:
document.body.addEventListener('click', (e) => {
console.log(findParentNode(e.target, '.param-input'));
});
2020-12-06 00:58
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);
2020-12-06 00:58
<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);
2020-12-06 01:01
Concise and quick (tested with Benchmark.js ) way to search for closest element by any css selector:
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.
2020-12-06 01:02
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 Sizzle for the DOM queries) :
// 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>
2020-12-06 01:04
To add an updated answer, there is now Element.closest(<query_selector>)
available.
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+.