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

javascript - Display none some content and block one element - Stack Overflow

programmeradmin5浏览0评论

I would like to make 3 buttons with each one make all the content div to display: none and depending on the button you have click one of the content div change to display: block. For example, If I click on the second button It will show only the second div content.

function showPanel(id) {

  var elements = document.getElementsByClassName("content");

  for (let i = 0; i < elements.length; i++) {
    document.getElementById(i).style.display = "none";
  }

  document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>

<div class="content">
  <div id="1" class="content">
    <p>TEST1</p>
  </div>
  <div id="2" class="content">
    <p class="other">TEST2</p>
  </div>
  <div id="3" class="content ">
    <p class="other">TEST3</p>
  </div>
</div>

I would like to make 3 buttons with each one make all the content div to display: none and depending on the button you have click one of the content div change to display: block. For example, If I click on the second button It will show only the second div content.

function showPanel(id) {

  var elements = document.getElementsByClassName("content");

  for (let i = 0; i < elements.length; i++) {
    document.getElementById(i).style.display = "none";
  }

  document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>

<div class="content">
  <div id="1" class="content">
    <p>TEST1</p>
  </div>
  <div id="2" class="content">
    <p class="other">TEST2</p>
  </div>
  <div id="3" class="content ">
    <p class="other">TEST3</p>
  </div>
</div>

Share Improve this question edited Feb 3, 2022 at 10:20 Brandon McConnell 6,1391 gold badge24 silver badges39 bronze badges asked Feb 3, 2022 at 9:56 Alejandro SánchezAlejandro Sánchez 691 gold badge5 silver badges12 bronze badges 1
  • 4 elements.length() is not a function, it is a property. Try using .length instead! – stacj Commented Feb 3, 2022 at 9:56
Add a ment  | 

5 Answers 5

Reset to default 2

There's a couple of issues in your code. Firstly length is a property, not a method, so you don't need the () suffix to invoke it. Secondly, there's no className attribute in HTML. This should just be class. Lastly the parent container shares the same class as the elements you're hiding, so all the child elements get hidden, even if they have display: block applied to them.

With these issues corrected, your code would look like this:

function showPanel(id) {
  var elements = document.getElementsByClassName("panel");
  for (let i = 0; i < elements.length; i++) {
    elements[i].style.display = "none";
  }
  document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('p1')">test1</button>
<button onclick="showPanel('p2')">test2</button>
<button onclick="showPanel('p3')">test3</button>

<div class="content">
  <div id="p1" class="panel">
    <p>TEST1</p>
  </div>
  <div id="p2" class="panel">
    <p class="other">TEST2</p>
  </div>
  <div id="p3" class="panel">
    <p class="other">TEST3</p>
  </div>
</div>

However it's worth noting that using onX attributes is outdated and not good practice. A better solution would be to use unobtrusive event handlers and provide custom metadata to the event handler through data attributes placed on the elements.

The improved version of the logic would look like this:

let buttons = document.querySelectorAll('button');
let panels = document.querySelectorAll('.panel');

buttons.forEach(button => {
  button.addEventListener('click', e => {
    panels.forEach(panel => {
      panel.style.display = panel.id === e.target.dataset.panel ? 'block' : 'none';
    });
  }); 
});
<button data-panel="1">test1</button>
<button data-panel="2">test2</button>
<button data-panel="3">test3</button>

<div class="content">
  <div id="1" class="panel">
    <p>TEST1</p>
  </div>
  <div id="2" class="panel">
    <p class="other">TEST2</p>
  </div>
  <div id="3" class="panel">
    <p class="other">TEST3</p>
  </div>
</div>

No need for JS or Jquery. Instead of a button you can use an anchor tag. Then you calling with the anchor the id of the element. Last but not least you make the boxes hidden through CSS and use the :target selector to display the elements:

.content {
  display: none;
}

.content:target {
  display: block;
}
<a href="#1">test1</a><br>
<a href="#2">test2</a><br>
<a href="#3">test3</a><br>

<div class="content-container">
  <div id="1" class="content">
    <p>TEST1</p>
  </div>
  <div id="2" class="content">
    <p class="other">TEST2</p>
  </div>
  <div id="3" class="content ">
    <p class="other">TEST3</p>
  </div>
</div>

Multiple issues.

  • Length can be calculated using elements.length and not elements.length()
  • You have given same class name to both the parent and the child divs. So hiding all elements with class name content will hide your whole parents itself. So after updating style.display = "block" to the required target, it will not work. Because your parent is already style.display = "none". So you should make a logic update there. So I changed the parent class name.

function showPanel(id) {
  var elements = document.getElementsByClassName("content");
  for (let i = 0; i < elements.length; i++) {
    elements[i].style.display = "none";
  }
  document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>

<div>
  <div id="1" class="content">
    <p>TEST1</p>
  </div>
  <div id="2" class="content">
    <p class="other">TEST2</p>
  </div>
  <div id="3" class="content ">
    <p class="other">TEST3</p>
  </div>
</div>

A more elegant way I might approach a prob,problem like this would be to tie the panels and their triggers together using data-attributes. This way, you don't risk conflicts with other IDs that m ay be the same on the page (IDs should always be unique).

Before setting up my event listener, I would initialize an openPanel variable and set it to any panel that is already created with the active class name. Whenever we open a new panel, we will overwrite this variable vaklue, so we don't need to do a new querySelctor each time.

Then, in the CSS, rather than hiding all panels and then showing the one with the active class, we can write a single style that hides any panels without the active class using the :not negation selector.

This is how that would look (initializing this with panel #1 open by default, but you can simply remove the active class from it in the HTML if you don't want that):

let openPanel = document.querySelector('[data-panel-id].active');

document.addEventListener('click', e => {
  if (e.target?.matches?.('[data-panel-target]')) {
    const id = e.target.dataset.panelTarget;
    if (id) {
      const panel = document.querySelector(`[data-panel-id="${id}"]`);
      if (panel) {
        openPanel?.classList.remove('active');
        panel.classList.add('active');
        openPanel = panel;
      }
    }
  }
})
[data-panel-id]:not(.active) {
  display: none;
}
<button data-panel-target="1">test1</button>
<button data-panel-target="2">test2</button>
<button data-panel-target="3">test3</button>

<main>
  <div data-panel-id="1" class="active">
    <p>TEST #1</p>
  </div>
  <div data-panel-id="2">
    <p>TEST #2</p>
  </div>
  <div data-panel-id="3">
    <p>TEST #3</p>
  </div>
</main>

I already submitted a separate solution with my preferred remendation, but I wanted to provide an answer to your question using the same approach you started with so as not to deviate from the code you already have in place.

The code you already had in place was actually fairly close to working already. The main issue I saw was that you were using document.getElementById(i) where you should actually have been using elements[i]. We can improve this further though, by replacing the for loop with a for..of loop, and determining inline whether the current element being evaluated is the one we want to show. If so, we use 'block', otherwise 'none'.

After initializing our function, we can call it on one of our IDs within the JS to have one panel open by default. **It's also important that the parent of all these .content elements NOT contain the class name content as well, as that would conflict with your function. I have replaced that parent element with a simple <main>…</main> element.

Here is how I would achieve solving this using your existing approach:

function showPanel(contentId) {
  const elements = Array.from(document.getElementsByClassName('content'));
  for (const element of elements) {
    element.style.display = element.id === contentId ? 'block' : 'none';
  }
}
showPanel('1');
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>

<main>
  <div id="1" class="content">
    <p>TEST1</p>
  </div>
  <div id="2" class="content">
    <p>TEST2</p>
  </div>
  <div id="3" class="content ">
    <p>TEST3</p>
  </div>
</main>

发布评论

评论列表(0)

  1. 暂无评论