Построение массива на основе иерархического дерева узлов

#javascript #html #dom

#javascript #HTML #dom

Вопрос:

У меня есть следующая разметка HTML:

 <body>
   <div class="wrapper">
      <div class="head">
         <p class="title">title</p>
         <a href="#" class="logo"></a>
      </div>
   </div>
</body
 

Мне нужно получить что-то вроде следующего — элемент «A» с классом «logo» является вторым дочерним узлом элемента div с классом «head». Элемент div с классом «head» является первым дочерним узлом элемента div с классом «wrapper», элемент div с классом «wrapper» является первым дочерним узлом body. Тогда я бы получил местоположение ссылки с классом «logo» следующим образом:

var a = [1, 1, 2]

Итак, если я пойду в противоположном направлении, используя приведенный выше массив, я найду ссылку с классом «logo» в DOM, начиная с элемента body. Кто-нибудь может сказать мне, как этого можно достичь с помощью JavaScript?

Заранее спасибо.

Комментарии:

1. Вы должны знать, что пробелы между узлами элементов в большинстве реализаций приводят к тому, что текстовые узлы существуют как дополнительные дочерние узлы. например, в вашем примере div class=»head» имеет текстовый дочерний узел, дочерний узел элемента, текстовый дочерний узел, дочерний узел элемента и текстовый дочерний узел в большинствереализации. Поэтому попытка индексировать узлы элементов в childNodes коллекции может быть сложнее, чем вы думаете в настоящее время. Однако в наши дни существует children коллекция, которая содержит только дочерние узлы элементов, поэтому в зависимости от ваших потребностей вы можете рассмотреть возможность использования этой коллекции.

2. Спасибо. Есть примеры? Я просто не могу понять, как это можно подсчитать.

3. @cycero вы не можете. Вам следует избегать предположений о позиции в .childNodes на основе HTML.

Ответ №1:

Вот пара функций, адаптированных из некоторого существующего моего кода, чтобы превратить узел в массив вложенных позиций внутри узла и обратно.

Живая демонстрация: http://jsfiddle.net/DSNUv /

Код:

 function getNodeIndex(node) {
    var i = 0;
    while( (node = node.previousSibling) ) {
        i  ;
    }
    return i;
}

function nodeToPath(node, rootNode) {
    var path = [], n = node;
    rootNode = rootNode || document.documentElement;
    while (n amp;amp; n != rootNode) {
        path.push(getNodeIndex(n));
        n = n.parentNode;
    }
    return path;
}

function pathToNode(path, rootNode) {
    rootNode = rootNode || document.documentElement;
    var node = rootNode;
    var i = path.length, nodeIndex;

    while (i--) {
        nodeIndex = path[i];
        if (nodeIndex < node.childNodes.length) {
            node = node.childNodes[nodeIndex];
        } else {
            throw new Error("Child node index out of range: "   nodeIndex);
        }
    }

    return node;
}
 

Пример использования:

 var a = document.getElementsByTagName("a")[0];

var path = nodeToPath(a, document.body);
alert(path);

var el = pathToNode(path, document.body);
alert(el.className);
 

Ответ №2:

Учитывая следующий HTML:

 <body>
   <div class="wrapper">
      <div class="head">
         <p class="title">title</p>
         <a href="#" class="logo"></a>
      </div>
   </div>
</body

var el = document.body; // body
var div = document.body.firstChild; // div.wrapper
el === div.parentNode; // body === body
var div2 = div.firstElementChild; // div.head
div2.parentNode.parentNode === el; // body === body
var p = div2.firstElementChild; // p.title
var a = p.nextElementSibling; // a.logo
div2.children[1] === a; // a === a
 

Я не совсем уверен, чего вы пытаетесь достичь. Но я рекомендую вам просто ходить по дереву, а не создавать отношения в каком-то массиве.