Я хочу написать фрагмент кода, который будет проходить через document.body страницы и сообщать обо всех пустых узлах DOM на уровне блоков. Это пропуск для SEO/a11y.
Я нашел эту статью, которая, казалось бы, поможет:
https://css-tricks.com/snippets/jquery/check-for-empty-elements/
$('*').each(function() {
if ($(this).is(':empty') == "") {
//Do Something
}
});
Вопрос № 1: Как мне преобразовать .is(':empty') в vanilla js:
function isEmpty(el) {
// Robust isEmpty logic here
}
document.querySelectorAll('*').filter(el => {
return isEmpty(el);
});
Вопрос № 2: Будет ли эта логика проходить через всех дочерних элементов?
Вопрос № 3: Можем ли мы сделать этот querySelector только для элементов блочного уровня?
@ TJCrowder спасибо за семантическое разъяснение Javascript/Jquery поверх DOM. Я обновил заголовок вопроса. И да, один вопрос на вопрос, извините за нарушение правил SO. Более того, спасибо за такой четкий ответ. Прекрасная работа!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Версия ДОМ "пустой" заключается в том, что нет дочерних узлов, что можно проверить различными способами, вероятно, наиболее распространенными являются два:
Так, например, поскольку null ложно и filter работает с истинными/ложными значениями:
const allEmpty = [...document.querySelectorAll('*')].filter(el => !el.firstChild);
(Обратите внимание, что querySelectorAll возвращает NodeList, а NodeList не имеет метода filter, поэтому я использовал расширенную нотацию для создания массива из NodeList [поскольку NodeLists теперь являются повторяемый в соответствии со спецификацией; но см. этот ответ о том, что NodeList является повторяемый в вашей среде].)
Question #2: Will this logic traverse all children too?
querySelectorAll('*') выбирает элемент каждый в документе, многие из которых будут находиться внутри других, а также в списке.
Question #3: Could we make this querySelector for only blocklevel elements?
Вы, безусловно, можете настроить его в соответствии с текущей спецификацией, и браузеры display по умолчанию применяются к ним, выполнив список тегов, таких как querySelectorAll("div, p, h1"/*...*/). Но это не говорит вам, что такое блочный элемент на этой странице, поскольку CSS может изменить display элементов. Чтобы получить актуальную информацию, вам нужно будет использовать getComputedStyle для каждого элемента после его выбора и проверить display результата.
Создание списка все элементов на странице может быть не идеальным, вместо этого вы можете рассмотреть рекурсивную функцию:
function findEmpty(element, results = []) {
let child = element.firstChild;
if (!child) {
results.push(element);
}
while (child) {
if (child.nodeType === Node.ELEMENT_NODE) {
findEmpty(child, results);
}
child = child.nextSibling;
}
return results;
}
const allEmpty = findEmpty(document.body);
Но это частично сводится к тому, что вы считаете «пустым». Селектор jQuery :empty довольно буквален: элемент пуст только в том случае, если у него нет дочерних узлов. Но ваше определение может быть более расплывчатым — например, возможно, вы хотите считать элемент, который содержит только пробелы (непосредственно или в дочерних элементах), «пустым» для ваших целей (в этом случае: !el.textContent.trim()). Первая ссылка выше относится к информации DOM на MDN, которая дает вам много возможностей для изучения, чтобы определить свой собственный «пустой», если это необходимо.
Вы можете использовать children, который отличается от childNodes, который может содержать любой узел, включая текстовый узел. Если использовать childNodes.length на div, как <div>Some Text here</div>, будет возвращен непустой массив, даже если нет дочерних элементов или тегов html.
function isEmpty(el) {
return el.children.length
}
[...document.querySelectorAll('div.parent')].filter(function(el) {
let k = isEmpty(el);
console.info(k)
});<div class='parent'>
<div>Child 1</div>
<div>Child 1</div>
<div>Child 1</div>
<div>Child 1</div>
</div>
<div class='parent'></div>Но кто посчитал бы <div>Lots of text here</div> «пустым»?
Я думаю, что childnodes в этом тексте будет непустой массив, если цель состоит в том, чтобы выбрать только дочерние элементы, но не текстовые узлы
Верно. Я хочу сказать, что приведенный выше div не пуст, но если вы используете children, он будет считаться пустым.
В SO важно задавать один вопроса на вопрос, а не три. Вопрос № 3 выше, в частности, довольно далек от вопроса № 1.