简体   繁体   English

我们如何通过外部点击关闭切换菜单

[英]How can we close a toggle menu with an outside click

I'm new to coding, I am have a made a decent looking website ( https://garibpathshala.in/ ) with a toggle nav menu for mobiles.我是编码新手,我有一个外观不错的网站( https://garibpathshala.in/ ),带有一个用于移动设备的切换导航菜单。

is there any way so that if we click outside the menu it'll close the menu.有什么办法可以让我们在菜单外单击它会关闭菜单。

Please have a look at my code and help me:)请查看我的代码并帮助我:)

HTML HTML

      <ul class="header-nav-links">
    <li class="active"><a href="https://garibpathshala.in">HOME</a></li>
    <li><a href="#projects_section">PROJECTS</a></li>
    <li><a href="#meet_the_team_section">TEAM</a></li>
    <li><a href="#about_us_section">ABOUT</a></li>
    <li><a href="https://gallery.garibpathshala.in">GALLERY</a></li>
    <li><a href="https://contact.garibpathshala.in">CONTACT</a></li>
    <li><a href="https://donate.garibpathshala.in">DONATE</a></li>
    <li><a href="https://join.garibpathshala.in">JOIN US</a></li>
   </ul>
  
   <div class="burger">
      <div line1></div>
      <div line2></div>
      <div line3></div>
    </div>

JS JS

const burger = document.querySelector(".burger");
const navLinks = document.querySelector(".header-nav-links");
const links = document.querySelectorAll(".header-nav-links li");

//Toggle Nav
burger.addEventListener("click", () => {
    navLinks.classList.toggle("open");

//Animate Links
links.forEach((link, index) => {
    if (link.style.animation) {
        link.style.animation = ""
    }else{
        link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7+0.2}s`;
    }
});
});

Here is a screenshot of the nav menu这是导航菜单的屏幕截图

You could add a click listener on body or document and rely on event delegation to take the appropriate action, as in the sample code below.您可以在bodydocument上添加一个单击侦听器,并依靠事件委托来采取适当的操作,如下面的示例代码所示。

(See the in-code comments for further clarification.) (有关进一步说明,请参阅代码内注释。)

 // Selects some DOM elements and converts the collection to an array const listItems = Array.from(document.querySelectorAll(".header-nav-links > li")); // Calls `handleMenuDisplay` when anything is clicked document.addEventListener("click", handleMenuDisplay); // Defines `handleMenuDisplay` function handleMenuDisplay(event){ // Listeners can access their triggering events const clickedThing = event.target; // The event's `target` property is useful // Depending on what was clicked, takes an appropriate action if(listItems.includes(clickedThing)){ // Arrays have an `includes` method openMenu(clickedThing); } else{ closeMenu(); } } function openMenu(clickedLi){ demo.textContent = clickedLi.dataset.demoText; } function closeMenu(){ demo.textContent = "Menu is closed"; }
 li{ margin: 7px; padding: 3px; border: 1px solid grey; } #demo{ margin-left: 2ch; font-size: 1.5em; font-weight: bold; }
 <ul class="header-nav-links"> <li data-demo-text="Home menu is open">HOME</li> <li data-demo-text="Projects menu is open">PROJECTS</li> <li data-demo-text="Team menu is open">TEAM</li> <li data-demo-text="About menu is open">ABOUT</li> </ul> <p id="demo">Menu is closed</p>

Note: My use of custom data-attributes was just to make the sample code a bit cleaner -- it's not part of event delegation, and the display text for each li could just have easily been written out manually in the script.注意:我使用自定义数据属性只是为了让示例代码更简洁——它不是事件委托的一部分,并且每个li的显示文本可以很容易地在脚本中手动写出。

Based on the other solutions:基于其他解决方案:

An even simpler way is to use the focus and blur states of DOM elements to handle the state for your menu.更简单的方法是使用 DOM 元素的焦点和模糊状态来处理菜单的 state。

 document.querySelectorAll('.menu').forEach((menu) => { const items = menu.querySelector('.menu-items'); menu.addEventListener('click', (e) => { items.classList.remove("hide"); menu.focus(); // Probably redundant but just in case; }). menu,addEventListener('blur'. () => { items.classList;add("hide"); }); });
 .menu { cursor: pointer; display: inline-block; }.menu > span { user-select: none; }.menu:focus { outline: none; border: none; }.hide { display: none; }.menu-items > * { user-select: none; }
 <div class="menu" tabindex="0"> <span>Menu +</span> <div class="menu-items hide"> <div>Item 0</div> <div>Item 1</div> <div>Item 2</div> </div> </div>

The secret here is to give the .menu div a tabindex so that it's focusable by the browser.这里的秘诀是给.menu div 一个tabindex ,这样它就可以被浏览器聚焦。

First things first for the JS:首先是 JS:

  • Search the page for any instance of the menu class document.querySelectorAll在页面中搜索菜单 class document.querySelectorAll的任何实例
  • Get the items element that's currently hidden by .hide获取当前被.hide隐藏的 items 元素
  • When somebody clicks on the menu remove the .hide class from the items当有人点击菜单时,从项目中删除.hide class
    • This should focus the div, but just in case menu.focus is called!这应该聚焦 div,但以防万一menu.focus被调用!
  • Then whenever somebody loses focus of the div, AKA clicks away etc. Add the .hide class back.然后,每当有人失去 div 的焦点时,AKA 就会点击等。添加.hide class 回来。

This could be expanded to change the text of the button, do all sorts of other things.这可以扩展为更改按钮的文本,做各种其他的事情。 It also keeps your code super clean because you're relying on the browsers own internal state management, so you don't have to do any checks.它还使您的代码保持超级干净,因为您依赖于浏览器自己的内部 state 管理,因此您无需进行任何检查。

Handle a second click close处理第二次点击关闭

Right so it works great, but in order to make it function as most people expect UI we need to close it when the menu div is clicked again too (replace span with any class you need):没错,它工作得很好,但是为了使它成为 function,因为大多数人期望 UI 我们需要在再次单击菜单 div 时关闭它(将span替换为您需要的任何 class):

...
    menu.querySelector('span').addEventListener('click', (e) => {
        e.stopPropagation();
        menu.blur();
    });

    menu.addEventListener('click', (e) => {
        items.classList.remove("hide");
        menu.focus(); // Probably redundant but just in case!
    });

    menu.addEventListener('blur', () => {
        items.classList.add("hide");
    });
...

You could remove "open" class from the menu if the event.CurrentTarget is not the hamburger menu and anything else in the document (html or body) is clicked.如果event.CurrentTarget不是汉堡菜单并且单击了文档中的任何其他内容(html 或正文),则可以从菜单中删除“打开”class。

You would also need to stopImmediatePropagation on the .hamburger and navLinks itself to stop those from being registered as clicks to the body, since they are children of the body and the event would otherwise bubble up to the body.您还需要在stopImmediatePropagationnavLinks本身上.hamburger以阻止那些被注册为对身体的点击,因为它们是身体的孩子,否则事件会冒泡到身体。 MDN reference: https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles MDN 参考: https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles

 const burger = document.querySelector(".burger"); const navLinks = document.querySelector(".header-nav-links"); const links = document.querySelectorAll(".header-nav-links li"); const body = document.querySelector('html'); //Toggle Nav burger.addEventListener("click", (e) => { navLinks.classList.toggle("open"); e.stopImmediatePropagation(); //Animate Links links.forEach((link, index) => { if (link.style.animation) { link.style.animation = ""; }else{ link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7+0.2}s`; } }); }); navLinks.addEventListener("click", (eve) => { eve.stopImmediatePropagation(); }); body.addEventListener("click", (ev) => { if (ev.currentTarget.= burger) { navLinks.classList;remove("open"); } });
 .burger { display: block; cursor:pointer; }.header-nav-links { display: block; }.header-nav-links.open { transform: translateX(0%); }.header-nav-links { right: 0; position: fixed; height: 92vh; top: 16vh; background-color: rgba(0, 0, 0, 0.7); display: flex; flex-direction: column; align-items: center; width: 50%; transform: translateX(100%); transition: transform 0.5s ease-in; }.header-nav-links li { list-style-type: none; }.header-nav-links li:hover { border: 1px solid #fff; border-radius: 6pc; background-color: #007bff; }.header-nav-links a { color: whitesmoke; text-decoration: none; font-family: Arial, sans-serif; font-weight: normal; font-size: 16px; border: 0px solid white; transition: 400ms; padding: 5px 15px; border-radius: 19px; }
 <ul class="header-nav-links"> <li class="active"><a href="https://garibpathshala.in">HOME</a></li> <li><a href="#projects_section">PROJECTS</a></li> <li><a href="#meet_the_team_section">TEAM</a></li> <li><a href="#about_us_section">ABOUT</a></li> <li><a href="https://gallery.garibpathshala.in">GALLERY</a></li> <li><a href="https://contact.garibpathshala.in">CONTACT</a></li> <li><a href="https://donate.garibpathshala.in">DONATE</a></li> <li><a href="https://join.garibpathshala.in">JOIN US</a></li> </ul> <div class="burger"> BURGER <div line1></div> <div line2></div> <div line3></div> </div>

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

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