admin管理员组

文章数量:1401176

With the press of a button, I want to toggle the class .active on the next div.bottom. These are basically accordions, but with a different structure.
Using nextElementSibling I guess won't work here to select the target element. How would one select such an element, that's neither a child nor a sibling (in plain JS)?

<div class="wrapper">
  <div class="top">
    <div class="inner">
      <div><button></button></div>
    </div>
  </div>
  <div class="bottom"></div>
</div>

<div class="wrapper">
  <div class="top">
    <div class="inner">
      <div><button></button></div>
    </div>
  </div>
  <div class="bottom"></div>
</div>

With the press of a button, I want to toggle the class .active on the next div.bottom. These are basically accordions, but with a different structure.
Using nextElementSibling I guess won't work here to select the target element. How would one select such an element, that's neither a child nor a sibling (in plain JS)?

<div class="wrapper">
  <div class="top">
    <div class="inner">
      <div><button></button></div>
    </div>
  </div>
  <div class="bottom"></div>
</div>

<div class="wrapper">
  <div class="top">
    <div class="inner">
      <div><button></button></div>
    </div>
  </div>
  <div class="bottom"></div>
</div>

Share Improve this question edited May 7, 2021 at 8:49 David Malášek 1,4321 gold badge11 silver badges24 bronze badges asked May 7, 2021 at 6:22 FluxiumFluxium 1103 silver badges10 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

I'd do it by using closest to go up to the container .wrapper element, then querySelector to find the bottom element:

function onClick(event) {
    const wrapper = event.target.closest(".wrapper");
    const bottom = wrapper && wrapper.querySelector(".bottom");
    if (bottom) {
        bottom.classList.toggle("active");
    }
}

Live Example:

// I've added event delegation here
document.body.addEventListener("click", function onClick(event) {
    const button = event.target.closest(".inner button");
    const wrapper = button && button.closest(".wrapper");
    const bottom = wrapper && wrapper.querySelector(".bottom");
    if (bottom) {
        bottom.classList.toggle("active");
    }
});
.active {
    color: blue;
    border: 1px solid black;
}
<div class="wrapper">
        <div class="top">
                <div class="inner">
                        <div><button>Button A</button></div>
                </div>
        </div>
        <div class="bottom">Bottom A</div>
</div>

<div class="wrapper">
        <div class="top">
                <div class="inner">
                        <div><button>Button B</button></div>
                </div>
        </div>
        <div class="bottom">Bottom B</div>
</div>

Or the same thing using optional chaining (relatively new):

function onClick(event) {
    const wrapper = event.target.closest(".wrapper");
    const bottom = wrapper?.querySelector(".bottom");
    bottom?.classList.toggle("active");
}

Live Example:

// I've added event delegation here
document.body.addEventListener("click", function onClick(event) {
    const button = event.target.closest(".inner button");
    const wrapper = button?.closest(".wrapper");
    const bottom = wrapper?.querySelector(".bottom");
    bottom?.classList.toggle("active");
});
.active {
    color: blue;
    border: 1px solid black;
}
<div class="wrapper">
        <div class="top">
                <div class="inner">
                        <div><button>Button A</button></div>
                </div>
        </div>
        <div class="bottom">Bottom A</div>
</div>

<div class="wrapper">
        <div class="top">
                <div class="inner">
                        <div><button>Button B</button></div>
                </div>
        </div>
        <div class="bottom">Bottom B</div>
</div>

By using closest() you can traverse the DOM upwards. With this it's easy to just get the relevant .bottom and toggle the active class on this element.

document.querySelectorAll('button').forEach(button => {
  button.addEventListener('click', (e) => {
    e.currentTarget.closest('.wrapper').querySelector('.bottom').classList.toggle('active');
  });
});
.bottom {
  display: none
}

.bottom.active {
  display: block
}
<div class="wrapper">
  <div class="top">
    <div class="inner">
      <button type="button">Toggle</button>
    </div>
  </div>
  <div class="bottom">Hidden content</div>
</div>
<div class="wrapper">
  <div class="top">
    <div class="inner">
      <button type="button">Toggle 2</button>
    </div>
  </div>
  <div class="bottom">Hidden content 2</div>
</div>

本文标签: javascriptGet next element with class (that39s not a child or sibling)Stack Overflow