querySelector для выбора ближайшего родителя для элементов h1 и p+p - возможно ли это?

РЕДАКТИРОВАТЬ Структура неизвестна - она ​​должна работать для любого новостного сайта, где есть контейнер / оболочка, которая содержит h1 и p+p (все, что связано с основной статьей этой страницы)

То, что я хочу, также может быть достигнуто с

let story = document.querySelector('p+p').parentElement;
while(!story.querySelector('h1')){
    story = story.parentElement;
}
console.log(story);

Но мне интересно, есть ли лучшее решение?

Каждая новостная статья имеет тег h1 и параграфы с текстом. Мне интересно, можно ли написать querySelector, который выберет ближайший родительский / контейнерный элемент, который содержит h1 и p + p. Хитрость в том, что он должен работать с любым новостным сайтом...


когда я пишу

document.body.querySelector('* h1')

Я могу получить контейнер h1, но на странице может быть несколько тегов h1 в соответствии с HTML5

Я знаю о querySelectorAll, но это не поможет в моем случае


когда я пишу

document.body.querySelector('* p+p').parentElement

Я могу получить контейнер для тела статьи с абзацами текста


Мой вопрос: возможно ли объединить эти два примера в один запрос? (без цикла и нескольких запросов) Что-то вроде...

document.body.querySelector('* ~ h1 ~ p+p')
document.body.querySelector('* h1 p+p')

... но работоспособный

3 ответа

Мой вопрос: возможно ли объединить эти два примера в один запрос?

ДЛ: Нет, это не так. Конечно, не сегодня, и, вероятно, не в ближайшее время. Если вас не интересует что-то кроме практического ответа, это все, что вам нужно знать; все, что за этим абзацем, является справочной информацией, относящейся к функции, которой еще нет в стандарте.


Это зависит от того, что вы подразумеваете под "одним запросом". Вы имеете в виду "одно назначение"? Если так, то :has() Псевдокласс от jQuery, предназначенный для стандартизации в Selectors 4, очень поможет:

// In jQuery: $('p+p').closest(':has(h1)')
let story = document.querySelector('p+p').closest(':has(h1)');

Но обратите внимание, что он используется в сочетании с Element#closest(), и, кроме того, :has() пока не поддерживается изначально, и в ближайшем будущем не планируется внедрять его в любом браузере. Так что, если JQuery не вариант, то у вас есть лучшее, что у вас есть в течение длительного времени.

Если под "одним запросом" вы подразумеваете "один селектор", то ответ "нет", потому что невозможно написать селектор, соответствующий ближайшему общему предку двух или более потомков. Ближайшим будет :has(h1):has(p+p), но это будет соответствовать каждому такому предку, начиная с самого внутреннего из них и вплоть до корневого элемента. Не существует селектора для сопоставления только самых внутренних из них.

Я создал решение JQuery.

Фрагмент стека

$('.block').each(function(e) {
  if ($(this).find('h4').length > 0 && $(this).find('p+p').length > 0) {
    console.log('block ' + (e + 1))
  }
});
body {
  font: 13px Verdana;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="block vv">
  <h4>heading</h4>
  <p>para1</p>
  <p>para2</p>
</div>
<div class="block">
  <h4>heading</h4>
  <p>para1</p>
</div>
<div class="block">
  <h4>heading</h4>
  <p>para1</p>
  <p>para2</p>
</div>

Я надеюсь, что это поможет вам!

Основываясь на сайте, который вы предоставили, просто используйте выбор ребенка и родного брата. Следующее будет работать.

window.document.querySelector("*>h1, * p+p").parentNode

Он выбирает все элементы с h1 и все элементы с несколькими тегами p. Я попробовал это на странице, которую вы предоставили, и это дало тот же результат, что и ваш код JS.

Несколько дополнительных замечаний, поскольку вы не указали jquery, я дал вам решение на JavaScript. В настоящее время нет родительского селектора или querySelector, поэтому parentNode является наиболее близким к этому. Наконец, ваше оригинальное решение указало статью (а не div, как на странице). Если вы хотите этого, просто поменяйте местами div для статьи.

Другие вопросы по тегам