#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;
outsideif
, который проверяет, является ли это неопределенным.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. Спасибо! Также не могли бы вы помочь связать его с кнопкой? Я имею в виду, что функция должна вызываться на странице при нажатии кнопки, а элемент, с которого начинается отображение дерева, указывается его идентификатором, который вводится в текстовое поле.