简体   繁体   English

添加删除 class 部分到现有的事件监听器循环

[英]Adding remove class section to existing eventlistener loop

What I am trying to do, is loop through all my.nav__btn elements, use them as buttons through the addEventListener, and through that add the class.open to certain elements.我想做的是循环遍历所有 my.nav__btn 元素,通过 addEventListener 将它们用作按钮,然后将 class.open 添加到某些元素。

This part actually works fine, and I even managed to make it remove the.open class from other elements, when a new one is triggered.这部分实际上工作正常,我什至设法让它在触发新元素时从其他元素中删除 .open class 。

However, I have tried in multiple ways now to make it remove the.open class, if the same button is pressed again.但是,如果再次按下同一个按钮,我现在已经尝试了多种方法让它删除 .open class。

I have tried using:我试过使用:

if (sections[x].classList.contains('open')) { 
    sections.classList.remove('open')
}

in different locations of the function, but without success.在 function 的不同位置,但没有成功。 Either it breaks the script or simply has no effect.它要么破坏脚本,要么根本没有效果。

my only solution is creating a completely seperate function to handle this matter, and have 2 EventListeners on the same elements, but I think it can be worked into this script.我唯一的解决方案是创建一个完全独立的 function 来处理这个问题,并在相同的元素上有 2 个 EventListener,但我认为它可以用于此脚本。 I just do not have the skills to do so, aparently.显然,我只是没有这样做的技能。

Below a complete snippet:下面是一个完整的片段:

 var btns = document.querySelectorAll('.nav__btn'); var sections = document.querySelectorAll('section'); for (var i = 0; i < btns.length; i++) { (function(x) { btns[x].addEventListener('click', _ => { if (sections[x].classList.contains('open')) { sections[x].classList.remove('open') } sections.forEach(section => { if (section.classList.contains('open')) { section.classList.remove('open') } }) sections[x].classList.toggle('open') }) })(i) }
 section { position: absolute; top: 0; right: 0; height: 50vh; width: 50vw; opacity: 0; visiblity: 0; z-index: 30; } section:nth-child(2) { background: #00ff00; } section:nth-child(3) { background: #ff0000; } section:nth-child(4) { background: #0000ff; } section:nth-child(5) { background: #ccc; }.open { opacity: 1; visibility: 1; }
 <nav class="nav"> <ul class="nav__list"> <li><span class="nav__btn">Button 1</span></li> <li><span class="nav__btn">Button 2</span></li> <li><span class="nav__btn">Button 3</span></li> <li><span class="nav__btn">Button 4</span></li> </ul> </nav> <section>section 1</section> <section>section 2</section> <section>section 3</section> <section>section 4</section>

Additionaly, here is a JsFiddle link: https://jsfiddle.net/ajLxbqzk/4/此外,这是一个 JsFiddle 链接: https://jsfiddle.net/ajLxbqzk/4/

To handle correctly sections display, you can loop through them this way:要正确处理部分显示,您可以通过这种方式循环:

  • If a section is associated to the button, toggle its display如果某个section与按钮相关联,则切换其显示
  • Otherwise, hide it否则,隐藏

Below a working version:下面是一个工作版本:

var btns = document.querySelectorAll('.nav__btn');
var sections = document.querySelectorAll('section');

// We loop through all buttons in the btns collection
// "i" is the index of the current button processed in the loop
btns.forEach((btn, i) => {
  btn.addEventListener('click', _ => {
    // If btns[i] is clicked, loop through sections...
    sections.forEach((section, j) => {
      if (i == j) {
        // The current section is of index i (because i == j)
        // We toogle it
        section.classList.toggle('open');
      } else {
        // Other sections are just hided
        section.classList.remove('open');
      }
    });
  });
});

This is your click handler code:这是您的点击处理程序代码:

  //1
  if (sections[x].classList.contains('open')) {
    sections[x].classList.remove('open')
  }

  //2
  sections.forEach(section => {
    if (section.classList.contains('open')) {
      section.classList.remove('open')
    }
  })

  //3
  sections[x].classList.toggle('open')

I labeled it into three steps.我把它标记为三个步骤。 When you click a button, these three things happen:当你点击一个按钮时,会发生这三件事:

  1. If the current section was open, close it.如果当前部分已打开,请将其关闭。
  2. Close all open sections.关闭所有打开的部分。
  3. Toggle the current section.切换当前部分。

Step 1 is redundant because step 2 closes all sections anyway - the end result will always be all sections being closed.第 1 步是多余的,因为第 2 步无论如何都会关闭所有部分 - 最终结果将始终是所有部分都被关闭。

Since step 2 ensures that all sections are always closed by the time you reach step 3, step 3 only can possibly do one thing: set the current section to open.由于第 2 步确保在您到达第 3 步时所有部分始终关闭,因此第 3 步只能做一件事:将当前部分设置为打开。 The current section can never be open at this point - because it was just closed in both step 1 and 2 - so sections[x].classList.toggle('open') can't possibly do anything other than make the section open.当前部分此时永远无法打开 - 因为它刚刚步骤 1 和 2 中关闭 - 所以sections[x].classList.toggle('open')除了打开该部分之外不可能做任何事情。

What you've described as what you want to happen is not the function that you wrote.你所描述的你想要发生的不是你写的 function 。 What you want is something like this:你想要的是这样的:

  1. Close all other sections.关闭所有其他部分。
  2. Toggle the current section.切换当前部分。

Because that way, when step 2 runs, the current section might still be open, therefore toggling it sets it to closed.因为这样,当第 2 步运行时,当前部分可能仍处于打开状态,因此切换它会将其设置为关闭。 So all you have to do is write it exactly as described:因此,您所要做的就是完全按照描述编写它:

  //1 - close all sections EXCEPT sections[x]
  sections.forEach(section => {
    if (section != sections[x] && section.classList.contains('open')) {
      section.classList.remove('open')
    }
  })

  //2 - toggle sections[x]
  sections[x].classList.toggle('open')

Here it is in your complete example:这是您的完整示例:

 var btns = document.querySelectorAll('.nav__btn'); var sections = document.querySelectorAll('section'); for (var i = 0; i < btns.length; i++) { (function(x) { btns[x].addEventListener('click', _ => { //1 - close all sections EXCEPT sections[x] sections.forEach(section => { if (section.= sections[x] && section.classList.contains('open')) { section.classList.remove('open') } }) //2 - toggle sections[x] sections[x].classList.toggle('open') }) })(i) }
 section { position: absolute; top: 0; right: 0; height: 50vh; width: 50vw; opacity: 0; visiblity: 0; z-index: 30; } section:nth-child(2) { background: #00ff00; } section:nth-child(3) { background: #ff0000; } section:nth-child(4) { background: #0000ff; } section:nth-child(5) { background: #ccc; }.open { opacity: 1; visibility: 1; }
 <nav class="nav"> <ul class="nav__list"> <li><span class="nav__btn">Button 1</span></li> <li><span class="nav__btn">Button 2</span></li> <li><span class="nav__btn">Button 3</span></li> <li><span class="nav__btn">Button 4</span></li> </ul> </nav> <section>section 1</section> <section>section 2</section> <section>section 3</section> <section>section 4</section>

I really don't like using loops in code.我真的不喜欢在代码中使用循环。 It creates messy code and looping over elements takes time.它会创建混乱的代码并且遍历元素需要时间。 I prefer storing variables instead.我更喜欢存储变量。

I removed your inner method that had x as an argument.我删除了以x作为参数的内部方法。 Instead, I changed var i in your loop to let i , otherwise i would have the value of 4 inside the anonymous click method.相反,我将循环中的var i更改为let i ,否则 i 将在匿名单击方法中具有 4 的值。

I created a content element as a container for all the sections which I which added "content" as an id.我创建了一个内容元素作为所有部分的容器,我将“内容”添加为 id。

I then just add the attribute previous-index to content and let that keep track of which section that was previously opened and let an if statement decide if I should remove the open class or not.然后,我只需将属性previous-index添加到内容中,让它跟踪之前打开的部分,并让 if 语句决定我是否应该删除open的 class。 I could use a global variable outside of the click methods but using global variables are always in the risk of being overwritten in larger projects.我可以在点击方法之外使用全局变量,但使用全局变量在较大的项目中总是有被覆盖的风险。

I'm using sectionIsOpen and newButtonClicked in order to explain code through variables, because it's harder to read "not statements", like i != previouslyClickedIndex .我正在使用sectionIsOpennewButtonClicked来通过变量解释代码,因为它更难阅读“非语句”,例如i != previouslyClickedIndex

Finally, you're using the wrong values on visibility .最后,您在visibility上使用了错误的值。 It should be hidden or visible , not 0 or 1.它应该是hiddenvisible ,而不是 0 或 1。

 const btns = document.querySelectorAll('.nav__btn'); const sections = document.querySelectorAll('section'); const content = document.getElementById('content'); for (let i = 0; i < btns.length; i++) { btns[i].addEventListener('click', () => { const NOT_SET = -1; let previouslyClickedIndex = content.getAttribute('previous-index') || NOT_SET; let sectionIsOpen = previouslyClickedIndex;= NOT_SET; let newButtonClicked = i.= previouslyClickedIndex. if (sectionIsOpen && newButtonClicked) { sections[previouslyClickedIndex];classList.remove('open'). } sections[i];classList.toggle('open'), content;setAttribute('previous-index'; i); }); }
 section { position: absolute; top: 0; right: 0; height: 50vh; width: 50vw; opacity: 0; visiblity: hidden; z-index: 30; } section:nth-child(2) { background: #00ff00; } section:nth-child(3) { background: #ff0000; } section:nth-child(4) { background: #0000ff; } section:nth-child(5) { background: #ccc; }.open { opacity: 1; visibility: visible; }
 <nav class="nav"> <ul class="nav__list"> <li><span class="nav__btn">Button 1</span></li> <li><span class="nav__btn">Button 2</span></li> <li><span class="nav__btn">Button 3</span></li> <li><span class="nav__btn">Button 4</span></li> </ul> </nav> <content id="content"> <section>section 1</section> <section>section 2</section> <section>section 3</section> <section>section 4</section> </content>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM