скрыть все элементы до определенного элемента

с jQuery и имея контейнер-обертку вокруг содержимого в пределах каждого h1, я мог бы скрыть их.

но без контейнера-контейнера, как это сделать?

какой лучший способ сделать что-то, что просто скрывает все до следующего h1?

Я не использую jQuery, потому что это часть приложения React.

h1 {
  border-bottom: solid 1px #000;
}

span {
  float: right;
}
<h1>h1 <span>x</span></h1>
<p>test 1</p>
<h2>h2</h2>
<p>test 2</p>

<h1>h1-1 <span>x</span></h1>
<p>test 3</p>
<h2>h2-2</h2>
<p>test 4</p>

Ответ 1

Я могу сделать это с помощью этого css. Просто добавьте класс "start" в h1, из которого вы хотите начать свертывание элементов и класса "вверх" до h1, до которого вы хотите, чтобы элементы разрушались.

CSS

.start ~ *:not(h1) {
   display: none;
}

.upto ~ * {
  display: block !important;
}

HTML

<h1 class='start'>h1 <span>x</span></h1>
 ...
<h1 class ='upto'>h1-1 <span>x</span></h1>

Здесь все элементы между началом и вверх будут скрыты. Вы можете получить эффект коллапса, добавив соответственно классы "старт" и "вверх"

Добавление класса к следующему h1 может быть также выполнено с помощью Javascript. Итак, у меня может быть простая js-функция, которая устанавливает "start" и "upto".

function collapse(startHeaderNumber, uptoHeaderNumber) {
    var allHeaders = document.getElementsByTagName("h1");
    var totalNoOfHeaders = allHeaders.length;

   if (startHeaderNumber > totalNoOfHeaders) {
       return;
   }

   var startHeader = allHeaders[startHeaderNumber - 1];
   startHeader.classList.add('start');

   if (uptoHeaderNumber <= totalNoOfHeaders) {
      var uptoHeader = allHeaders[uptoHeaderNumber - 1];
      uptoHeader.classList.add('upto');
   }

}

И вы можете просто называть это как

collapse(1 ,2)

И это разрушит все элементы между заголовками 1 и 2. Или вы можете называть это так,

collapse(1)

который скроет все элементы из первого заголовка до последнего.

Для полной демонстрации, пожалуйста, см. Эту скрипку

Ответ 2

похоже, что вы хотите что-то подобное функции jQuery nextUntil(). Вот хорошее руководство для этого в vanilla js. Код выглядит следующим образом:

var nextUntil = function (elem, selector, filter) {

    // Setup siblings array
    var siblings = [];

    // Get the next sibling element
    elem = elem.nextElementSibling;

    // As long as a sibling exists
    while (elem) {

        // If we've reached our match, bail
        if (elem.matches(selector)) break;

        // If filtering by a selector, check if the sibling matches
        if (filter && !elem.matches(filter)) {
            elem = elem.nextElementSibling;
            continue;
        }

        // Otherwise, push it to the siblings array
        siblings.push(elem);

        // Get the next sibling element
        elem = elem.nextElementSibling;

    }

    return siblings;

};

Я, очевидно, не знаю контекста, стоящего за тем, что вы делаете, но я считаю, что это лучше, изменяя HTML. Это потенциально может позволить вам сделать некоторые из них с помощью только селекторов css nth child

Ответ 3

Вы можете использовать previousElementSibling рекурсивно, чтобы получить всех братьев и сестер ваших элементов h1. Вот рабочий пример с использованием previousElementSibling:

const elems = document.getElementsByTagName('h1');

for (let i = 0; i < elems.length; i++) hidePrev(elems[i]);

function hidePrev(elem)
{
    var pre = elem.previousElementSibling;
    if (!pre) return;
    pre.style.display = 'none';
    hidePrev(pre);
}
h1 {
  border-bottom: solid 1px #000;
}

span {
  float: right;
}
<h1>h1 <span>x</span></h1>
<p>test 1</p>
<h2>h2</h2>
<p>test 2</p>

<h1>h1-1 <span>x</span></h1>
<p>test 3</p>
<h2>h2-2</h2>
<p>test 4</p>

Ответ 4

Я прокомментировал код. И я надеюсь, вы понимаете, что здесь происходит, но если нет, просто напишите ниже.

function hideUntilNextSiblingWithSameName(elementName) {
  /*
   * @Param {elementName: String} 
   * Hide all elements until the next one with the same name
   */
  var trackH1 = 0,
      element = document.getElementsByTagName(elementName)[0],
      node = element.parentNode.firstChild;

  do {
    // Keep truck of element with the same name.
    if (node.tagName === element.tagName) trackH1 += 1;

    // Stop if catch element with same name
    if (trackH1 == 2) break;

    // Do not hide link, script, style and text node
    if (node.nodeType === 3 || node.tagName === "LINK" || node.tagName === "SCRIPT" || node.tagName === "STYLE") continue;
    // Hide element
    else {
      node.style.visibility = "hidden";
    }
  } while (node = node.nextSibling)
}

hideUntilNextSiblingWithSameName("h1")
<h1>h1 <span>x</span></h1>
<p>test 1</p>
<h2>h2</h2>
<p>test 2</p>

<h1>h1-1 <span>x</span></h1>
<p>test 3</p>
<h2>h2-2</h2>
<p>test 4</p>

<link rel="stylesheet" href="">
<script></script>
<style></style>

Ответ 5

Вы можете сделать это проще, например, следующим образом. Идея состоит в том, чтобы найти непосредственного родителя узлов, body в этом случае и найти всех его непосредственных потомков.

Затем начните удаление элементов, пока мы не найдем нужный элемент. В этом примере я попытался скрыть элементы, но вы можете просто изменить код, чтобы удалить их.

Ниже приведена рабочая демонстрация:

const elems = document.querySelectorAll('body > *');
const elemBefore = document.querySelectorAll('h1')[1];

for (let i = 0; i < elems.length; i++) {
  let elem = elems[i];

  if (elem === elemBefore) {
    break;
  }

  elem.style.display = 'none';
}
h1 {
  border-bottom: solid 1px #000;
}

span {
  float: right;
}
<h1>h1 <span>x</span></h1>
<p>test 1</p>
<h2>h2</h2>
<p>test 2</p>

<h1>h1-1 <span>x</span></h1>
<p>test 3</p>
<h2>h2-2</h2>
<p>test 4</p>

Ответ 6

Возможно, вы можете использовать трюк и скрыть

за h1 и h2 через css:

const selector = document.querySelectorAll('h1, h2');
const clickH = function (event) {
   const h = event.target;
   const attr = h.getAttribute('class');
   if (attr === '') {
      h.setAttribute('class', 'closed')
      return undefined;
   }
   h.setAttribute('class', '')
}
selector.forEach((h) => {
    h.setAttribute('class', 'closed')
    h.addEventListener('click', clickH);
})
h1, h2 {
  position: relative;
  border-bottom: solid 1px #000;
  background-color: #fff;
  height: 50px;
  border-bottom: solid 1px #000;
  display: block;
  z-index: 2;
  margin-bottom: 0;
}

.closed {
  margin-bottom: -50px;
}

p {
  height: 30px;
  
}

span {
  float: right;
}
<h1>h1 <span>x</span></h1>
<p>test 1</p>
<h2>h2</h2>
<p>test 2</p>

<h1>h1-1 <span>x</span></h1>
<p>test 3</p>
<h2>h2-2</h2>
<p>test 4</p>