Я искал функцию, которая возвращала бы "расстояние" между элементами в DOM с точки зрения предков, братьев и сестер и потомков. Например, предположим, что у меня было:
<div id="div1">
<div id="div5"></div>
</div>
<div id="div2">
<div id="div6">
<div id="div9"></div>
</div>
<div id="div7"></div>
</div>
<div id="div3"></div>
<div id="div4">
<div id="div8">
<div id="div10"></div>
</div>
</div>
то мне нужна функция, которая вернет расстояние между #div5
и #div10
как-то вроде:
{
up: 1,
across: 3,
down: 2
}
Так как для перехода из #div5
в #div10
вам нужно подняться на одно поколение, перейдите 3 брата (до #div4
), а затем вниз 2 поколения. Аналогично, #div9
в #div1
вернется:
{
up: 2,
across: -1,
down: 0
}
для восхождения на два поколения, а затем назад одного брата.
У меня уже есть функция, которая делает это (что я буду включать в качестве ответа ниже), поэтому я включаю его здесь, потому что: а) я думал, что кто-то может найти его полезным; и б) может быть, у кого-то есть лучший способ сделать это.
Хорошо, вот что у меня для этого. Я надеюсь, что он достаточно хорошо объяснил в комментариях кода:
function DOMdistance(elem1,elem2) {
if (elem1 === elem2) {
return {
up: 0,
across: 0,
down: 0
};
}
var parents1 = [elem1],
parents2 = [elem2],
gens = 1,
sibs = 0,
sibElem;
// searches up the DOM from elem1 to the body, stopping and
// returning if it finds elem2 as a direct ancestor
while (elem1 !== document.body) {
elem1 = elem1.parentNode;
if (elem1 === elem2) {
return {
up: parents1.length,
across: 0,
down: 0
};
}
parents1.unshift(elem1);
}
// reset value of elem1 for use in the while loop that follows:
elem1 = parents1[parents1.length - 1];
// searches up the DOM from elem2 to the body, stopping and
// returning if it finds elem1 as a direct ancestor
while (elem2 !== document.body) {
elem2 = elem2.parentNode;
if (elem2 === elem1) {
return {
up: 0,
across: 0,
down: parents2.length
};
}
parents2.unshift(elem2);
}
// finds generation depth from body of first generation of ancestors
// of elem1 and elem2 that aren't common to both
while (parents1[gens] === parents2[gens]) {
gens++;
}
sibElem = parents1[gens];
// searches forward across siblings from the earliest non-common ancestor
// of elem1, looking for earliest non-common ancestor of elem2
while (sibElem) {
sibElem = sibElem.nextSibling;
if (sibElem && sibElem.tagName) {
sibs++;
if (sibElem === parents2[gens]) {
return {
up: parents1.length - gens - 1,
across: sibs,
down: parents2.length - gens - 1
};
}
}
}
sibs = 0;
sibElem = parents1[gens];
// searches backward across siblings from the earliest non-common ancestor
// of elem1, looking for earliest non-common ancestor of elem2
while (sibElem) {
sibElem = sibElem.previousSibling;
if (sibElem && sibElem.tagName) {
sibs--;
if (sibElem === parents2[gens]) {
return {
up: parents1.length - gens - 1,
across: sibs,
down: parents2.length - gens - 1
};
}
}
}
}
Так, например, получение "расстояния" от #div5
до #div10
в DOM, описанном в вопросе, будет использовать что-то вроде:
var divOne = document.getElementById('div5'),
divTwo = document.getElementById('div10'),
distance = DOMdistance(divOne, divTwo);
и поэтому distance
было бы:
{
up: 1,
across: 3,
down: 2
}