Как получить всех предков элемента в DOM-дереве с помощью JavaScript
Стало интересно как получить всех возможных предков элемента (и их общее количество) с заданным id?
Например, так мы можем найти всех потомков элемента:
let item = document.getElementById('menu');
for (let i in item.children){
console.log(`${ item.children[i] }`);
}
<html>
<body>
<h3>Переменные и типы</h3>
<p>Тип переменной определяется типом заносимого в нее значения.</p>
<div id="menu">
<p class="bold">JavaScript поддерживает следующие типы данных:</p>
<ul>
<li>число;</li>
<li>строка;</li>
<li>массив;</li><li>объект.</li>
</ul>
<div>Допускается взаимное преобразование типов.</div>
</div>
</body>
<div id="k"></div>]
</html>
А вот как получить предков вопрос)
Я попробовал так:
let item = document.getElementById('menu');
if(`${item.parentElement}` !== null) {
for(let i in item.parentElement) {
console.log(`${item.parentElement[i]}`);
}
}
<body>
<h3>Переменные и типы</h3>
<p>Тип переменной определяется типом заносимого в нее значения.</p>
<div id="menu">
<p class="bold">JavaScript поддерживает следующие типы данных:</p>
<ul>
<li>число;</li>
<li>строка;</li>
<li>массив;</li><li>объект.</li>
</ul>
<div>Допускается взаимное преобразование типов.</div>
</div>
</body>
<div id="k"></div>
Но выводит вообще все, что не надо. Я думаю, что ошибка в цикле)
Ответы (3 шт):
Вы пытаетесь перебирать свойства родительского элемента, а не подниматься вверх по дереву DOM. Вероятно, решением будет что-то вроде:
let item = document.getElementById('menu');
let ancestors = [];
if (item) {
let currentParent = item.parentElement;
while (currentParent) {
ancestors.push(currentParent);
currentParent = currentParent.parentElement;
}
console.log("Предки элемента с id='menu':");
ancestors.forEach((ancestor, index) => {
let description = ancestor.tagName;
if (ancestor.id) description += `#${ancestor.id}`;
if (ancestor.className) description += `.${ancestor.className.split(' ').join('.')}`;
console.log(`${index + 1}: ${description}`, ancestor);
});
console.log(`\nОбщее количество предков: ${ancestors.length}`);
} else {
console.log("Элемент с id 'menu' не найден.");
}
<!DOCTYPE html>
<html>
<head>
<title>Пример</title>
</head>
<body>
<div id="for-test-div-1">
<h3>Переменные и типы</h3>
<p>Тип переменной определяется типом заносимого в нее значения.</p>
<div id="menu">
<p class="bold">JavaScript поддерживает следующие типы данных:</p>
<ul>
<li>число;</li>
<li>строка;</li>
<li>массив;</li>
<li>объект.</li>
</ul>
<div>Допускается взаимное преобразование типов.</div>
</div>
</div>
<div id="k"></div>
</body>
</html>
PS: "современные" браузеры автоматически переместят <div id="k"></div> внутрь <body>
Функция getParents принимает 2 параметра:
- HTML-элемент, для которого требуется определить цепочку родительских элементов;
- строку со стоп селектором, на котором нужно прекратить обход родителей.
Функция выполняет рекурсивный обход родителей до тех пор, пока не будет найден такой элемент в цепочке родителей, который соответствует селектору stopSelector. Если стоп-селектор не задан или в процессе обхода не будет найден родитель, соответствующий стоп-селектору, то обход будет производиться вплоть до корневого элемента DOM-дерева.
Функция возвращает объект с 3 свойствами:
parents- массив элементов в цепочке родителей, причем в начале массива - ближайший родитель, в конце - самый далекий родитель;selectorFound- булевое значение, которое примет true, если обход был остановлен по условию соответствия стоп-селектору;length- длина цепочки родителей.
PS: я взял вашу разметку и выполнил вызов getParents для элемента li с id=test для наглядности, т.к. он лежит "поглубже".
/**
* @param {HTMLElement} element
* @param {String} stopSelector
*/
function getParents(element, stopSelector) {
const parent = element.parentElement;
if (!parent) return {
parents: [],
selectorFound: false,
length: 0
}
if (stopSelector && parent.matches(stopSelector)) return {
parents: [parent],
selectorFound: true,
length: 1
}
const parentsOfParent = getParents(parent, stopSelector);
return {
parents: [parent, ...parentsOfParent.parents],
selectorFound: parentsOfParent.selectorFound,
length: 1 + parentsOfParent.length
}
}
const element = document.querySelector('#test');
const parents = getParents(element, 'body');
console.log(parents);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>Переменные и типы</h3>
<p>Тип переменной определяется типом заносимого в нее значения.</p>
<div id="menu">
<p class="bold">JavaScript поддерживает следующие типы данных:</p>
<ul>
<li>число;</li>
<li id="test">строка;</li>
<li>массив;</li>
<li>объект.</li>
</ul>
<div>Допускается взаимное преобразование типов.</div>
</div>
<script src="script.js"></script>
</body>
</html>
function getParents(el) {
const res = [];
while ((el = el.parentElement)) {
res.push(el);
}
return res;
}
document.body.addEventListener('click', e => {
console.log(getParents(e.target).map(x => x.outerHTML.replace(/>(?=.*\n).*/s, ">")).join("\n"));
})
<h3>Переменные и типы</h3>
<p>Тип переменной определяется типом заносимого в нее значения.</p>
<div id="menu">
<p class="bold">JavaScript поддерживает следующие типы данных:</p>
<ul>
<li>число;</li>
<li>строка;</li>
<li>массив;</li>
<li>объект.</li>
</ul>
<div>Допускается взаимное преобразование типов.</div>
</div>