简体   繁体   中英

How do I associate individual buttons with individual divs?

I am trying to set up a web page where I have a list of buttons, and each button toggles the visibility of a div directly below it.

The problem I am having is that all of my buttons only toggle the visibility of the last div in my page.

Here is the following relevant code:

HTML

<div class="menuItem">
    <button>Food Item</button>
    <div class="info">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <img src="../images/menu/spaghetti.jpg" alt="spaghetti">
    </div>
</div>
<div class="menuItem">
    <button>Food Item</button>
    <div class="info">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <img src="../images/menu/spaghetti.jpg" alt="spaghetti">
    </div>
</div>
<div class="menuItem">
    <button>Food Item</button>
    <div class="info">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <img src="../images/menu/spaghetti.jpg" alt="spaghetti">
    </div>
</div>

And here is my javascript:

"use strict";

(function() {
    var menuItems = document.getElementsByClassName("menuItem");

    for(var ii = 0; ii < menuItems.length; ii++) {
        var button = menuItems[ii].getElementsByTagName("button")[0];
        var info = menuItems[ii].getElementsByClassName("info")[0];
        button.onclick = function() {
            if(info.style.display === "block") {
                info.style.display = "none";
            } else {
                info.style.display = "block";
            }
        };
    }
})();

I don't think I totally understand what the javascript is doing under the hood. I think I'm getting references to each individual button, but it seems like when I change the onclick method for one button, I am changing the onclick method for all of them. Why is this happening, and how do I prevent this?

You can use jQuery to do so. You can define a function (let's call it toggleInfo and put it in onclick attribute like so:

<button onclick="toggleInfo()">Food Item</button>

And then in your function you can use .toggle() on the nearest element with class info

Try defining info within click handler using .nextElementSibling

 (function() { "use strict"; var menuItems = document.getElementsByClassName("menuItem"); for (var ii = 0; ii < menuItems.length; ii++) { var button = menuItems[ii].getElementsByTagName("button")[0]; button.onclick = function() { var info = this.nextElementSibling; if (info.style.display === "block") { info.style.display = "none"; } else { info.style.display = "block"; } }; } })(); 
 .info { display: none; } 
 <div class="menuItem"> <button>Food Item</button> <div class="info"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> <img src="../images/menu/spaghetti.jpg" alt="spaghetti"> </div> </div> <div class="menuItem"> <button>Food Item</button> <div class="info"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> <img src="../images/menu/spaghetti.jpg" alt="spaghetti"> </div> </div> <div class="menuItem"> <button>Food Item</button> <div class="info"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> <img src="../images/menu/spaghetti.jpg" alt="spaghetti"> </div> </div> 

Event Delegation

There is a much simpler way to do that. Add a parent container

<div id="container">
<div class="menuItem">
.....

Create a custom Click handler for the parent container

function handler(e){
 console.dir(e.target);//maybe console.log(e.target);
 // or console.dir(e.target.parentNode);
}
document.getElementById('container').addEventListener('click',handler,false);

Check console while you click. there are many useful informations about the clicked element's and it's parentNode


In your case:

function handler(e){
 if(e.target.nodeName=='BUTTON'){//if i click on the correct element
   e.target.parentNode.getElementsByClassName('info')[0].classList.toggle('view');
 }
}

classList nodeName parentNode target

here is the custom hide class.

.view{
 display:none;
}

I also would avoid display:none the browser needs to redraw the whole element everytime.think of top:-999999px; opacity:0; height:justthebuttonsize; transform:scale(0); top:-999999px; opacity:0; height:justthebuttonsize; transform:scale(0);

The cool part of this is that you have only one Event! No loops! And many more advantages. You don't even need document.getElementsByClassName if you navigate trough the nodes (which is much faster).Ahh and this is everything pure native javascript.

http://jsfiddle.net/z6kk5rxc/2/

if you don't understand something just ask

Using jQuery, this is simple:

$('.toggle').click(function() {
    $(this).next().toggle();
});

I added ' class="toggle" ' to each button. Here's a fiddle: https://jsfiddle.net/mckinleymedia/tx4tsvfa/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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