简体   繁体   中英

JavaScript - style.display not defined

Trying to get away from jQuery crutches and refactoring the bellow functions as plain JS.

 //slide toggle navigation 
 $('#nav-toggle').click(function () {
     $('.nav-list').slideToggle();
 });

   //toggle hamburger menu 
 $('#nav-toggle').click(function () {
    this.classList.toggle('active');
 });

I got the last one working as:

   const toggle = document.getElementById('nav-toggle');
   const navList = document.getElementsByClassName('nav-list');  

    toggle.addEventListener('click', function(e){
    this.classList.toggle('active'); //toggle hamburger menu 
    e.preventDefault();
    }, false);

I hit a blocker when I tried to pass both functionalities to the same click event:

//Add a click event listener
toggle.addEventListener('click', function(e){
    //show hide div
    if (navList.style.display == 'none') {
        navList.style.display === 'block';
    } else {
        navList.style.display === 'none';
    }    

    this.classList.toggle('active');
    e.preventDefault();
}, false);

I have .nav-list as display none in my CSS .

Do I need separate event listeners for each event? I tried that, but the error is still the same = TypeError: navList.style is undefined

Also, what would be the refactor for this nasty one bellow as plain JS?

 $('nav ul li a:not(:only-child)').click(function (e) {
        $(this).siblings('.nav-dropdown').toggle();
        // Close one dropdown when selecting another
        $('.nav-dropdown').not($(this).siblings()).hide();
        e.stopPropagation();
    });

You're out of jQuery, but you're still thinking in jQuery. navList is a NodeList object now, you need to iterate:

//Add a click event listener
toggle.addEventListener('click', function(e){
    //show hide div
    for( var i = 0; i < navList.length; ++i ){
        if (navList[i].style.display == 'none') {
            navList[i].style.display === 'block';
        } else {
            navList[i].style.display === 'none';
        }    
    }
    this.classList.toggle('active');
    e.preventDefault();
}, false);

Edit: This monstrosity should do the other fuction's job:

(function(){
    var navDropdown = document.getElementsByClassName('nav-dropdown');
    var nav = document.getElementsByTagName('nav');
    for( var i = 0; i < nav.length; ++i ){
        var ul = nav[i].getElementsByTagName('ul');

        for( var j = 0; j < ul.length; ++j ){
            var li = ul[j].getElementsByTagName('li');

            for( var m = 0; m < li.length; ++m ){
                var a = li[m].getElementsByTagName('a');

                if( a.length > 0 ){
                    for( var k = 0; k < a.length; ++k ){
                        a[k].addEventListener('click', (function(a){
                                return function(e){
                                    for( var n = 0; n < a.length; ++n ){
                                        a[n].classList.toggle('nav-dropdown');
                                    }   

                                    for( var o = 0; o < navDropdown.length; ++o ){
                                        var found = false;
                                        for( var n = 0; n < a.length; ++n ){
                                            if( navDropdown[o] === a[n] ){
                                                found = true;
                                                break;
                                            }
                                        }
                                        if( !found ){
                                            navDropdown[o].classList.add('hide');
                                        }
                                    }

                                    e.preventDefault();
                                };
                            })(a)
                        );
                    }
                }
            }
        }
    }
})();

It might very possibly be one of the worst things I've ever written, but it should work... Obviously I can't check if it does without the actual page, but at least it runs.

you can iterate over a node list by using Array.from which will treat it as an array.

Array.from(navList).forEach(function(navItem){
  navItem.style.display = navItem.style.display === 'none' ? 'block' : 'none';
})

You have the equal signs in your syntax crossed, should be:

if (navList.style.display === 'none') {
    navList.style.display = 'block';
} else {
    navList.style.display = 'none';
}

Quick cheat sheet:

= : assign

== : equals (also crosses javascript "type borders", ie 0 == "0" is true)

=== : strict equals (0 === "0" is false, 0 === 0 is true)

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