I know that this method may seem a bit crazy, but you can use the direct descendant selector >
next to the universal selector *
, to select all descendants of level N.
The universal selector is the least efficient and slowest, but in modern browsers (and limiting its scope to a part of the page in particular) its impact on the performance of the page should not be important. If you only want to work with div
, you could replace the *
below with div
and the result would be more efficient.
From that, you can make a function that creates a selector of N levels (for example, children would be #padre > *
, grandchildren would be #padre > * > *
, great grandchildren would be #padre > * > * > *
, and so on). For each level there should be a > *
.
Then we would have this function that would take as parameters the selector of the element from which we want to obtain its descendants, and a number specifying the level of the descendant:
function getDescendientesDeNivel(selector, nivel) {
// si no es un nivel válido, devolvemos false
if (!nivel || nivel < 1) { return false; }
// creamos un selector con el selector del elemento raíz y n veces "> *"
var selector = selector + Array(nivel + 1).join(" > *");
// devolvemos los elementos seleccionados
return document.querySelectorAll(selector);
}
And here's a demo:
function getDescendientesDeNivel(selector, nivel) {
if (!nivel || nivel < 1) { return false; }
var selector = selector + Array(nivel + 1).join(" > *");
return document.querySelectorAll(selector);
}
var hijos = getDescendientesDeNivel("#padre", 1);
var nietos = getDescendientesDeNivel("#padre", 2);
var bisnietos = getDescendientesDeNivel("#padre", 3);
var tataranietos = getDescendientesDeNivel("#padre", 4);
console.log(bisnietos);
<div id="padre">
<div id="hijo-1">
<div id="nieto-1">
</div>
</div>
<div id="hijo-2">
<div id="nieto-2">
<div id="bisnieto-1">
</div>
</div>
<div id="nieto-3">
</div>
</div>
<div id="hijo-3">
<div id="nieto-4">
</div>
<div id="nieto-5">
<div id="bisnieto-2">
</div>
</div>
</div>
</div>
This function can be used to extend the prototype of Node
(as suggested by Eduen in your answer ) , which could be done using :scope
to specify that you start searching from the active element:
Node.prototype.getDescendientesDeNivel = function(nivel) {
if (!nivel || nivel < 1) { return false; }
var selector = ":scope " + Array(nivel + 1).join(" > *");
return this.querySelectorAll(selector);
}
What you can see working here:
Node.prototype.getDescendientesDeNivel = function(nivel) {
if (!nivel || nivel < 1) { return false; }
var selector = ":scope " + Array(nivel + 1).join(" > *");
return this.querySelectorAll(selector);
}
var padre = document.getElementById("padre");
var hijos = padre.getDescendientesDeNivel(1);
var nietos = padre.getDescendientesDeNivel(2);
var bisnietos = padre.getDescendientesDeNivel(3);
var tataranietos = padre.getDescendientesDeNivel(4);
console.log(bisnietos);
<div id="padre">
<div id="hijo-1">
<div id="nieto-1">
</div>
</div>
<div id="hijo-2">
<div id="nieto-2">
<div id="bisnieto-1">
</div>
</div>
<div id="nieto-3">
</div>
</div>
<div id="hijo-3">
<div id="nieto-4">
</div>
<div id="nieto-5">
<div id="bisnieto-2">
</div>
</div>
</div>
</div>