Функция JavaScript, выводящая DOM-дерево страницы

#javascript #html #node.js

#javascript #HTML #node.js

Вопрос:

Мне нужно написать js-функцию, которая выводит DOM-дерево нажатием кнопки. Дерево должно выводиться в виде ненумерованного списка (ul) с вложениями, и необходимо использовать имя элемента, то есть head, body, p, div и т. Д., И идентификатор элемента в качестве текстового вывода в элементе списка (конечно, если он указан). Я думал, что это сработает, но есть некоторые «неопределенные» элементы, но их здесь не должно быть. Итак, я не понимаю, что не так

 function DOM_Tree(e) {
  for (let i = 0; i < document.body.childNodes.length - 1; i  ) {
    if (document.body.childNodes[i].id != 'tree') {
      let ul = document.getElementById('tree');
      let li = document.createElement('li');
      let el = document.body.childNodes[i];
      let ul1 = document.createElement('ul');
      if (el.hasChildNodes()) {
        li.innerText = document.body.childNodes[i].id;
        ul.append(li);
        for (let j = 0; j < el.childNodes.length; j  ) {
          if (el.childNodes[j].id != undefined) {
            let li1 = document.createElement('li');
            li1.innerText = el.childNodes[j].id;
            ul1.append(li1);
          }
          let li1 = document.createElement('li');
          li1.innerText = el.childNodes[j].id;
          ul1.append(li1);
        }
        ul.append(ul1);
      } else {
        if (document.body.childNodes[i].id != undefined) {
          li.innerText = document.body.childNodes[i].id;
          ul.append(li);
        }
      }
    }
  }
}
confirmButton.onclick = function() {
  DOM_Tree(document.body);
  alert('click');
}  
 <!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
</head>

<body>
  <div id="container1" style="background-color: cyan;">
    <h1 id="header1">Header</h1>
    <p id="paragraph1">Paragraph</p>
    <div id="container2" style="background-color: red;">
    </div>
  </div>
  <ul id="tree"></ul>
  <input type="text" id="formText">
  <br>
  <button id="confirmButton" style="margin-top: 5px;">Build a DOM tree</button>
</body>

</html>  

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

1. Ваша функция не является рекурсивной; она не может работать для произвольно глубокого DOM-дерева. Кроме того, вероятно, было бы неплохо вычислить новое «репрезентативное» дерево в памяти и только затем поместить его в DOM.

2. @AKX не могли бы вы, пожалуйста, помочь мне, как это сделать?

3. У вас есть li1.innerText = el.childNodes[j].id; outside if , который проверяет, является ли это неопределенным.

4. Почему вы делаете это дважды? Первый находится внутри if , второй — после.

5. @Barmar о, извините, я забыл прокомментировать это

Ответ №1:

Вот пара рекурсивных функций, которые сначала создают описание дерева в виде простых объектов, а затем выводят это описание в DOM-дерево UL / LI.

 function describeNode(node) {
  return {
    id: node.id,
    type: node.nodeType,
    text: node.textContent,
    children: [...node.childNodes].map(describeNode),
  };
}

function renderDescription(d) {
  const li = document.createElement("li");
  if (d.type === 3) { // Text node with content
    if (!d.text.trim().length) {
      return null; // Empty node, don't represent
    }
    li.appendChild(document.createTextNode(`text: `   d.text));
  } else {
    li.appendChild(document.createTextNode(`node of type ${d.type}, id ${d.id || '--'}`));
  }
  if (d.children amp;amp; d.children.length) {
    const childrenUl = document.createElement("ul");
    li.appendChild(childrenUl);
    d.children.map(renderDescription).forEach((c) => c amp;amp; childrenUl.appendChild(c));
  }
  return li;
}

const descr = describeNode(document.getElementById("source"));
document.getElementById("result_json").value = JSON.stringify(descr, null, 2);
document.getElementById("result_tree").appendChild(renderDescription(descr));  
 <main id="source">
  <div id="container1" style="background-color: cyan;">
    <h1 id="header1">Header</h1>
    <p id="paragraph1">Paragraph</p>
    <div id="container2" style="background-color: red;">
      <h2 id="header2">SubHeader</h1>
        <p id="paragraph2">Sub-Paragraph</p>
        <p id="paragraph3">Sub-Paragraph Two</p>
    </div>
  </div>
</main>
<textarea id="result_json"></textarea>
<ul id="result_tree"></ul>  

Ответ №2:

У вас есть этот блок кода дважды:

           let li1 = document.createElement('li');
          li1.innerText = el.childNodes[j].id;
          ul1.append(li1);
  

Первый находится внутри an if (el.childNodes[j].id != undefined) , поэтому он не будет печатать неопределенные идентификаторы. Второй после if , поэтому он печатает неопределенные идентификаторы.

Простое удаление второго блока избавляет от undefined маркеров.

Если вы хотите, чтобы во входных данных указывался идентификатор, с которого нужно начинать, используйте document.getElementById() в onclick функции. Затем измените DOM_Tree его на использование e вместо document.body в качестве начального элемента.

 function DOM_Tree(e) {
  for (let i = 0; i < e.childNodes.length - 1; i  ) {
    if (e.childNodes[i].id != 'tree') {
      let ul = document.getElementById('tree');
      let li = document.createElement('li');
      let el = e.childNodes[i];
      let ul1 = document.createElement('ul');
      if (el.hasChildNodes()) {
        li.innerText = e.childNodes[i].id;
        ul.append(li);
        for (let j = 0; j < el.childNodes.length; j  ) {
          if (el.childNodes[j].id != undefined) {
            let li1 = document.createElement('li');
            li1.innerText = el.childNodes[j].id;
            ul1.append(li1);
          }
        }
        ul.append(ul1);
      } else {
        if (e.childNodes[i].id != undefined) {
          li.innerText = e.childNodes[i].id;
          ul.append(li);
        }
      }
    }
  }
}
confirmButton.onclick = function() {
  let target = document.body; // default target
  let id = document.getElementById("formText").value;
  if (id) {
    target = document.getElementById(id);
    if (!target) {
      alert(`ID ${id} not found`);
      return;
    }
  }
  DOM_Tree(target);
}  
 <!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
</head>

<body>
  <div id="container1" style="background-color: cyan;">
    <h1 id="header1">Header</h1>
    <p id="paragraph1">Paragraph</p>
    <div id="container2" style="background-color: red;">
    </div>
  </div>
  <ul id="tree"></ul>
  <input type="text" id="formText" placeholder="ID to start at, default = document.body">
  <br>
  <button id="confirmButton" style="margin-top: 5px;">Build a DOM tree</button>
</body>

</html>  

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

1. Спасибо! Также не могли бы вы помочь связать его с кнопкой? Я имею в виду, что функция должна вызываться на странице при нажатии кнопки, а элемент, с которого начинается отображение дерева, указывается его идентификатором, который вводится в текстовое поле.