Pregunta ocultar todos los elementos antes del elemento específico


con jQuery y tener un contenedor envoltorio alrededor de los contenidos dentro de cada h1, podría ocultarlos fácilmente.

pero sin contenedor contenedor, ¿cómo lo haría uno?

¿Cuál es la mejor manera de hacer algo que simplemente oculta todo antes de la próxima h1?

No estoy usando jQuery porque esto es parte de una aplicación 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>

o envolver todo después y antes de la próxima h1 en una etiqueta div?


18
2018-05-28 18:37


origen


Respuestas:


Puedo hacerlo con este CSS. Simplemente agregue la clase "inicio" a la h1 desde la cual desea comenzar a contraer los elementos y la clase "hasta" a la h1 hasta la cual desea que los elementos colapsen.

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>

Aquí todos los elementos entre el inicio y el final estarán ocultos. Puede tener el efecto de colapso colocando la adición de las clases 'start' y 'upto' según corresponda

La adición de la clase a la próxima h1 también se puede hacer a través de Javascript. Entonces, puedo tener una función js simple que establece el 'inicio' y el 'hasta'.

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');
   }

}

Y simplemente puedes llamarlo así

collapse(1 ,2)

Y colapsaría todos los elementos entre los encabezados 1 y 2. O bien, puedes llamarlo así,

collapse(1)

que colapsará todos los elementos desde el primer encabezado hasta el último.

Para ver una demostración completa, mira esto violín


4
2018-06-08 11:07



Parece que quieres algo similar a jQuery nextUntil() función. Aquí hay una buena guía para hacer eso en vanilla js. El código termina luciendo así:

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;

};

Obviamente no conozco el contexto detrás de lo que estás haciendo, pero creo que hay una forma mejor de hacerlo alterando el HTML. Esto podría incluso permitirle hacer algo de esto con solo css enésimo selectores de niños


2
2018-05-28 18:50



Puedes usar previousElementSibling recursivamente para obtener todos los hermanos de su h1 elementos. Aquí está el ejemplo de trabajo usando 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>


1
2018-06-07 11:12



He comentado el código. Y espero que entiendas lo que está pasando aquí, pero si no, solo comenta abajo.

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>

https://codepen.io/anon/pen/QxGVNG


Por el momento, oculto los elementos. Pero si no quieres mostrar los elementos, usa node.style.display = "none"; en lugar de node.style.visibility = "hidden"; en la cláusula else


1
2018-06-08 13:50



Puedes hacer esto de una manera más simple como la siguiente. La idea es encontrar al padre inmediato de los nodos, body en este caso, y encuentre a todos sus hijos inmediatos.

Luego, comience a eliminar los elementos hasta que hayamos encontrado el elemento deseado. En este ejemplo, he intentado ocultar los elementos, pero simplemente puede cambiar el código para eliminarlos.

Lo que sigue es una demostración funcional:

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>


0
2018-06-06 06:00



Tal vez puedas usar un truco y esconder

 detrás de h1 y h2 a través de 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>


0
2018-06-06 13:57