[英]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`;
}
});
});
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.您可以在body
或document
上添加一个单击侦听器,并依靠事件委托来采取适当的操作,如下面的示例代码所示。
(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
的显示文本可以很容易地在脚本中手动写出。
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
,这样它就可以被浏览器聚焦。
document.querySelectorAll
在页面中搜索菜单 class document.querySelectorAll
的任何实例.hide
获取当前被.hide
隐藏的 items 元素.hide
class from the items当有人点击菜单时,从项目中删除.hide
class
menu.focus
is called!这应该聚焦 div,但以防万一menu.focus
被调用!.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 管理,因此您无需进行任何检查。
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.您还需要在stopImmediatePropagation
和navLinks
本身上.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.