简体   繁体   中英

Event.target alternatives

I try to make side navigation close on click somewhere but navigation block itself and its toggle button. I try such code:

HTML

<div class="header__menu-toggle">
    <div class="icon-menu"></div>
</div>
<section id="main-nav">
  <ul class="main-nav__inner">
    <li>one</li>
    <li>two</li>
    <li>three</li>
  </ul>
</section>

NATIVE JS

var body = document.getElementsByTagName("body")[0];
var nav = document.getElementById('main-nav');
var navToggle = document.getElementsByClassName('header__menu-toggle')[0];

function closeAll(e) {
    if (e.target != nav && e.target != navToggle) {
        nav.classList.remove("main-nav--open");
    }
}

body.addEventListener('click', closeAll)

The problem is that e.target equals to an exact target of click, not whole block. For ex. click on <div class="icon-menu"></div> is not equal click on its parent <div class="header__menu-toggle"> . Or click on child li elements deep in navigation block isn't equal to click on <section id="main-nav"> . How to solve this problem? How to check if I click on navigation block or navToggle block in common?

尝试:$(event.currentTarget)我认为这是解决方案,如果不尝试显示事件对象并找到事件的一些子属性,可以帮助您,此链接可以帮助event.currentTarget

I guess something like this may work.

Side note: querySelector and querySelectorAll are great, use them instead.

 var body = document.querySelector("body"); var nav = document.querySelector('#main-nav'); var navToggle = document.querySelector('.header__menu-toggle'); var nodeArr = [].slice.call(nav.childNodes); function closeAll(e) { if (nodeArr.indexOf(e.target) !== -1) { console.log('closing the nav') nav.classList.remove("main-nav--open"); } else { console.log('clicked inside nav') } } body.addEventListener('click', closeAll) 
 <div class="header__menu-toggle"> <div class="icon-menu"></div> </div> <section id="main-nav"> <ul class="main-nav__inner"> <li>one</li> <li>two</li> <li>three</li> </ul> </section> 

Why it works?

nav.childNodes stores information about all children of the nav element. We convert it to array for convenience. After click is detected we check if the click target belongs to the nav (is in the array).

Try to go up in DOM tree from target element.

 //function search for "search" element for "current" element and all his parents function isInside(search,current){ if (current!=search){ if (typeof current.parentNode != 'undefined' && current.parentNode!=null) return isInside(search,current.parentNode);//go to parent else return false;//our tree is over - this is outside element }else{ //yes this is element we looking for return true; } }; var search=document.querySelector("#container"); //usage document.querySelector("body").addEventListener("click",function(e){ if (isInside(search,e.target)){ console.log("click inside #container"); }else{ console.log("click outside #container"); } }); 
 <html> <body> <div> This is wrong div</div> <div id="container" width="100px" height="100px" style="display:block; background:red"><ul><li><span>Test node</span></li></ul> </div> <div> This is wrong div</div> </body> </html> 

Explanation - i start with e.target node and go up, there are to endings - one if we find parent which is matching searching element - this means we are inside or we are this element, or second we go to end of tree - we are outside.

This method can be improved by adding for example how much levels we should go up.

In this current problem usage of isInside function would be like this:

function closeAll(e) {
   if (!isInside(nav,e.target) && !isInside(navToggle,e.target) ) {
      nav.classList.remove("main-nav--open");
   }
}

you can use jquery method "closest"

$(document).click( function(event){
   if( $(event.target).closest("#main-nav").length ||           
       $(event.target).closest(".header__menu-toggle").length) return;

       $("#main-nav").removeClass("main-nav--open");  
}

event.path return array of tree structure which can be used to find parents of target element.

replace js code with :

    var body = document.getElementsByTagName("body")[0];
var nav = document.getElementById('main-nav');
var navToggle = document.getElementsByClassName('header__menu-toggle')[0];

function closeAll(event) {
    if (event.path.indexOf(nav) > -1 && event.path.indexOf(navToggle) > -1) {
        nav.classList.remove("main-nav--open");
    }
}

body.addEventListener('click', closeAll)

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