最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - hide all elements before specific element - Stack Overflow

programmeradmin7浏览0评论

with jQuery and having a wrapper container around the contents within each h1, I could easily hide them.

but with no wrapper container, how would one do it?

what's the best way to do something that just hides everything before the next h1?

I'm not using jQuery because this is part of a React app.

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>

with jQuery and having a wrapper container around the contents within each h1, I could easily hide them.

but with no wrapper container, how would one do it?

what's the best way to do something that just hides everything before the next h1?

I'm not using jQuery because this is part of a React app.

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>

or wrap everything after and before the next h1 in a div tag?

Share Improve this question edited Jun 3, 2018 at 12:25 totalnoob asked May 28, 2018 at 18:37 totalnoobtotalnoob 2,74110 gold badges39 silver badges72 bronze badges 1
  • If the number of subentries is very limited you could always just use the + operator: add some class (e.g. expanded) when it should be expanded and then just spam enough: h1.expanded+p, h1.expanded+p+p, h1.expanded+p+p+p, ... { ... } – Fabian N. Commented Jun 4, 2018 at 12:25
Add a ment  | 

6 Answers 6

Reset to default 4 +25

I am able to do it with this css. Just add the class "start" to the h1 from which you want to start collapsing the elements and the class "upto" to the h1 upto which you want the elements to collapse.

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>

Here all the elements between start and upto will be hidden. You can have the collapse effect by placing adding the 'start' and 'upto' classes accordingly

The addition of the class to the next h1 could be also done via Javascript. So, I can have a simple js function which sets the 'start' and the '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');
   }

}

And you can simply call it like

collapse(1 ,2)

And it would collapse all the items between headers 1 and 2. Or, you can call it like,

collapse(1)

which will collapse all elements from the first header till the last.

For a full demo, please see this fiddle

sounds like you want something similar to jQuery's nextUntil() function. Here is a good guide to doing that in vanilla js. The code ends up looking like this:

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;

};

I obviously don't know the context behind what you are doing, but I reckon there's a better way around it by altering the HTML. This could potentially even let you do some of this with just css nth child selectors

You can use previousElementSibling recursively to get all of the siblings of your h1 elements. Here is working example using 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>

I have mented the code. And I hope you understand what is going on here, but if not, just ment below.

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


At the moment, I hide the elements. But if you want to even not display the elements, use node.style.display = "none"; instead of node.style.visibility = "hidden"; in the else clause.

You can do this in a simpler way like the following. The idea is to find the immediate parent of the nodes, body in this case, and find all the immediate children of it.

Then, start removing the elements until we've found the desired element. In this example, I've tried to hide the elements, but you can simply change the code the remove them instead.

Following is a working demo:

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>

Maybe you can use a trick and hide the

behind the h1 and h2 via 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)

  1. 暂无评论