How to hide an element when clicking in another element who shares the same classes in vanilla JavaScript?

时间:2019-04-16 22:21:25

标签: javascript arrays onclick dom-events

I have created a toggle menu using vanilla javaScript because I am trying not to use jQuery as a dependency. I have been successful so far, but I want to toggle off the visibility of the other elements when clicking & opening a menu content.

HTML code for the markup:

<div class="menu-link">Menu 1</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

<br>

<div class="menu-link">Menu 2</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

<br>

<div class="menu-link">Menu 3</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

<br>

<div class="menu-link">Menu 4</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

CSS code for the styling of the toggle on/off effect of the menu content:

menu-link {
    display: inline-block;
    cursor: pointer;
    padding: 10px;
}

.menu-content {
    display: none;
}

.show {
    display: block;
    -webkit-animation-name: show;
    animation-name: show;
}

/* Show Animation */
@-webkit-keyframes show {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@keyframes show {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

.animated {
    -webkit-animation-duration: 1.3s;
    animation-duration: 1.3s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;
}

JavaScript code to toggle class on/off:

// var declaration
var menuLinks = document.querySelectorAll('.menu-link');

// Loop through the array & add a click event to toggle "show" class
for (var i = 0; i < menuLinks.length; i++ ) {
    menuLinks[i].addEventListener('click', function() {
        if(this.nextElementSibling.className.match("show") ) {
            this.nextElementSibling.classList.remove("show");
        } else {
            this.nextElementSibling.classList.add("show");
        }
    });
};

This is jsfiddle example

4 个答案:

答案 0 :(得分:1)

Short answer: You can simply get reference to the element which was clicked directly on your event listener and change visibility of all elements but the one which was clicked.

for (var i = 0; i < menuLinks.length; i++ ) {
  menuLinks[i].addEventListener('click', function(event) {
    const clickedElement = event.target;
    // remove show class from all elements but clicked element
    menuLinks.forEach(function(linkEl) {
      if (linkEl !== clickedElement) {
        linkEl.classList.toggle("show", false);
      } else {
        linkEl.classList.toggle("show", true);
      }
    });
  });
};

One problem I see here is that you are registering click listners on all the elements. You can optimize that by adding one click listener to a parent DOM node instead on each individual node.

答案 1 :(得分:1)

Inside the callback function you could loop through your array menuLinks, remove the show class from all siblings and finally add it to the sibling which parent fired the click event. Something like:

// var declaration
var menuLinks = document.querySelectorAll('.menu-link');

// Loop through the array & add a click event to toggle "show" class
for (var i = 0; i < menuLinks.length; i++) {
  menuLinks[i].addEventListener('click', function(e) {

    for (var a = 0; a < menuLinks.length; a++) {
      if (menuLinks[a] != e.target) {
        menuLinks[a].nextElementSibling.className = "menu-content animated";
      }

    }
    e.target.nextElementSibling.className = "show";
  });
};
menu-link {
  display: inline-block;
  cursor: pointer;
  padding: 10px;
}

.menu-content {
  display: none;
}

.show {
  display: block;
}

/* Show Animation */

@-webkit-keyframes show {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes show {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.show {
  -webkit-animation-name: show;
  animation-name: show;
}

.animated {
  -webkit-animation-duration: 1.3s;
  animation-duration: 1.3s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
<div class="menu-link">Menu 1</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

<br>

<div class="menu-link">Menu 2</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

<br>

<div class="menu-link">Menu 3</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

<br>

<div class="menu-link">Menu 4</div>

<p class="menu-content animated">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed quas odio facere sunt ullam quo ex amet sint in vitae.</p>

答案 2 :(得分:1)

You need to hide other elements in the DOM for this purpose. One way to do it:

JSFiddle

// var declaration
var menuLinks = document.querySelectorAll('.menu-link');

// Loop through the array & add a click event to toggle "show" class
for (var i = 0; i < menuLinks.length; i++ ) {
    var el = menuLinks[i]
  el.addEventListener('click', function() {
    var itemId = i;

      var allMenuLinks = document.querySelectorAll('.menu-link');

    if(this.nextElementSibling.className.match("show") ) {
      this.nextElementSibling.classList.remove("show");
    } else {
      this.nextElementSibling.classList.add("show");
    }

    for(var j=0; j<allMenuLinks.length; j++) {
        if(this==allMenuLinks[j]) {
        continue;
      }
      allMenuLinks[j].nextElementSibling.classList.remove("show");
    }
  })
}

答案 3 :(得分:0)

First you are creating a new function each time in loop so you should rather declare such function outside. The whole code might look like this:

var menuLinks = document.querySelectorAll('.menu-link');
var onClick = function () {
  var target = this;
  for (var i = 0, j = menuLinks.length; i < j; i++) {
    if (target === menuLinks[i]) {
      target.classList.add("show");
    } else {
      target.classList.remove("show");
    }
  }
};
// Loop through the array & add a click event to toggle "show" class
for (var i = 0, j = menuLinks.length; i < j; i++) {
    menuLinks[i].addEventListener('click', onClick);
}