[英]How do I add and remove classes to multiple child elements nested in an UL with a single click using Javascript?
我想首先為這么長的問題道歉,我只是希望我不會因此而難以理解。
我在 UL 中創建了一個帶有三個菜單元素的側欄,它們展開以顯示子元素、更改背景顏色並在單擊時刪除 hover 效果。 我通過定義一個 function 來做到這一點,它在單擊菜單元素時添加和刪除包含相關屬性的類。
我希望側邊欄執行但似乎無法執行的四件事如下;
我認為我的代碼最麻煩的地方是添加和刪除類,特別是考慮到嵌套在<li>
標簽內的<a>
標簽(點擊的元素)是“懸停” class 需要的地方被添加/刪除,以及展開的<ul>
標簽也嵌套在點擊的元素內。
function toggleMenu(e) { var kids = document.querySelector("#menuList").children; var unselectedLink = document.querySelectorAll(".unselected a"); var unselectedDropdown = document.querySelectorAll(".unselected ul"); //adds "unselected" class to all elements exept the selected one for (var i = 0; i < kids.length; i++) { kids[i].className = "unselected"; } //adds "menuHover" class to all elements exept the selected element for (var i = 0; i < unselectedLink.length; i++) { unselectedLink[i].className = "menuHover"; } for (var i = 0; i < unselectedDropdown.length; i++) { unselectedDropdown[i].classList.remove("show") } //adds "selected" class, removes "menuHover" class and adds "toggle" to the selected element e.className = "selected"; document.querySelector(".selected a").classList.remove("menuHover"); document.querySelector(".selected ul").classList.toggle("show"); }
.sidebar { position: fixed; width: 250px; height: 100%; left: 0px; top: 0; background: #1b1b1b; font-family: sans-serif; }.menu-bar { background: #1b1b1b; height: 60px; display: flex; align-items: center; padding-left: 42px; }.side-text { color: #C5C5C5; font-weight: bold; font-size: 20px; } nav ul { background: #1b1b1b; height: 100%; width: 100%; list-style: none; margin-left: 0; padding-left: 0; } nav ul li { line-height: 40px; } nav ul li a { position: relative; color: #C5C5C5; text-decoration: none; font-size: 14px; padding-left: 43px; font-weight: normal; display: block; width: 100%; } nav ul ul { position: static; display: none; } nav ul ul li a { font-family: sans-serif; font-size: 13px; color: #e6e6e6; padding-left: 80px; font-weight: lighter; }.submenu-item:hover { background: #1e1e1e;important. } /*...........selected and show..................*/:selected { background-color; #255DAA. }:show { display; block. } /*...........unselected and hover..................*/:unselected { color; #1e1e1e. }:menuHover:hover { color; #255DAA; }
<nav class="sidebar"> <div class="menu-bar"> <label class="side-text">MENU</label> </div> <ul id="menuList"> <li class="selected" onclick="toggleMenu(this)"> <a href="#" class="" id="staff-btn">Staff</a> <ul> <li><a href="#">New Staff</a></li> <li><a href="#">View Staff</a></li> </ul> </li> <li class="unselected" onclick="toggleMenu(this)"> <a href="#" id="notes-btn" class="menuHover">Notes</a> <ul> <li><a href="#">New Note</a></li> <li><a href="#">Edit Notes</a></li> </ul> </li> <li class="unselected" onclick="toggleMenu(this)"> <a href="#" class="menuHover" id="tasks-btn">Tasks</a> <ul> <li><a href="#">New Tasks</a></li> <li><a href="#">Edit Task</a></li> </ul> </li> </nav>
我非常接近,但不知何故,從邏輯上講,我在 JavaScript 上做錯了事情,因此對代碼進行任何調整以使其達到上述所有四個目標都將不勝感激。 謝謝
一個簡單的方法來做到這一點:
如果元素被選中,只需取消選中它
如果不是,請取消選擇所有元素和 select 被點擊的元素
function toggleMenu(el) {
if (el.classList.contains("selected")) {
el.classList.remove("selected");
el.classList.add("unselected");
}
else {
for (const child of document.getElementById("menuList").children) {
child.classList.remove("selected");
child.classList.add("unselected");
}
el.classList.remove("unselected");
el.classList.add("selected");
}
}
編輯 1您可以使用以下 css 取消隱藏所選菜單項的子菜單:
.selected ul {
display: block;
}
編輯 2我遇到了實際實施它的麻煩。
function toggleMenu(el) { if (el.classList.contains("selected")) { el.classList.remove("selected"); el.classList.add("unselected"); } else { for (const child of document.getElementById("menuList").children) { child.classList.remove("selected"); child.classList.add("unselected"); } el.classList.remove("unselected"); el.classList.add("selected"); } }
.sidebar { position: fixed; width: 250px; height: 100%; left: 0px; top: 0; background: #1b1b1b; font-family: sans-serif; }.menu-bar { background: #1b1b1b; height: 60px; display: flex; align-items: center; padding-left: 42px; }.side-text { color: #C5C5C5; font-weight: bold; font-size: 20px; } /* menu */.menu { background: #1b1b1b; height: 100%; width: 100%; list-style: none; margin-left: 0; padding-left: 0; }.menu-item { line-height: 40px; }.menu-item a { position: relative; color: #C5C5C5; text-decoration: none; font-size: 14px; padding-left: 43px; font-weight: normal; display: block; width: 100%; } /* submenu */.submenu { position: static; display: none; list-style: none; }.submenu-item a { font-family: sans-serif; font-size: 13px; color: #e6e6e6; padding-left: 80px; font-weight: lighter; }.submenu-item:hover { background: #1e1e1e; } /* selected and unselected */.selected { background-color: #255DAA; }.selected.submenu { display: block; }.unselected { color: #1e1e1e; }.unselected:hover a { color: #255DAA; }
<nav class="sidebar"> <div class="menu-bar"> <label class="side-text">MENU</label> </div> <ul class="menu" id="menuList"> <li class="menu-item selected" onclick="toggleMenu(this)"> <a href="#" id="staff-btn">Staff</a> <ul class="submenu"> <li class="submenu-item"><a href="#">New Staff</a></li> <li class="submenu-item"><a href="#">View Staff</a></li> </ul> </li> <li class="menu-item unselected" onclick="toggleMenu(this)"> <a href="#" id="notes-btn">Notes</a> <ul class="submenu"> <li class="submenu-item"><a href="#">New Note</a></li> <li class="submenu-item"><a href="#">Edit Notes</a></li> </ul> </li> <li class="menu-item unselected" onclick="toggleMenu(this)"> <a href="#" id="tasks-btn">Tasks</a> <ul class="submenu"> <li class="submenu-item"><a href="#">New Tasks</a></li> <li class="submenu-item"><a href="#">Edit Task</a></li> </ul> </li> </ul> </nav>
作為公認答案的替代方案,我正在研究兩種不同的方法......
#menuList li
是<a>
菜單項列表的容器,這些菜單項具有相鄰的<ul>
子菜單項。 為了使用 CSS 輕松選擇,我將 class .menu-item
分配給那些<a>
。
兩個版本的CSS 邏輯基本相同:
.menu-item
相鄰的ul
子菜單項默認隱藏:hover
colors.menu-item
和相鄰的ul
定義 colors ( :focus
或.selected
為真).menu-item
被選中時,使.menu-item
相鄰的ul
子菜單項可見(同上) 區別:對於 CSS,我們只使用:focus
選擇器,對於 CSS 和 Javascript,我們使用.selected
。
僅限 CSS (自動對焦和模糊)
單擊時<a>
獲得焦點(如按鈕、輸入等:focus
為true )。 當用戶在焦點元素之外單擊/點擊時,它會自動再次失去焦點(變得模糊並且:focus
為false ,如:not(:focus) = 'blur' )。 我們可以使用 CSS :focus
選擇器來處理用戶點擊和修改元素, MDN: ':focus' 。
CSS 和 Javascript (根據要求進行聚焦和模糊)
OP 希望選定的.menu-item
及其相鄰的ul
子菜單項保持可見,直到用戶再次明確取消選擇它。 這不能使用:focus
選擇器完成,因此我們忽略該選擇器並使用 class .selected
代替自己處理焦點和模糊要求, MDN:HTMLElement.blur() 。
Javascript 邏輯相當簡單:
將“click”- eventListener
( MDN: Element: click event ) 附加到主容器#menuList
處理:
.menu-item
被選中並且它是當前的.selected
然后模糊它( menuItemBlur()
).menu-item
時,首先模糊它( menuItemBlur()
).menu-item
( menuItemFocus()
)操作代碼的更改
class
屬性<#menuList li a>
中的href="#"
更改為href="javascript:void(0)"
以防止它在瀏覽器歷史記錄中創建條目(子菜單項仍將創建條目)。下面的代碼片段被大量評論,應該是不言自明的。
'use-strict'; var activeItem; // Holds the currently '.selected''.submenu' (null/undefined if none) // Attach 'click' event listener to the #menuList document.getElementById('menuList').addEventListener('click', function(e) { menuItemToggle(e.target) }); function menuItemToggle(el) { if (el.classList.contains('menu-item2')) { // When a '.menu-item' gets clicked (not its kids) if (el.classList.contains('selected')) { // and it is the '.selected''.menu-item' menuItemBlur(el); // then close it and remove focus() } else { if (activeItem) // When there is a currently selected '.menu-item' menuItemBlur(activeItem); // then deactivate it menuItemFocus(el); // Now activate the clicked `.menu-item` }; }; function menuItemBlur(el) { el.classList.remove("selected"); // Set the '.menu-item' to not '.selected' activeItem = null; // and remove the reference to it el.blur(); // Remove focus from element for CSS ':focus' //...extend with other 'Blur' stuff... }; function menuItemFocus(el) { el.classList.add("selected"); // Set the '.menu-item' to '.selected' activeItem = el; // and save a reference to it //...extend with other 'Focus' stuff... }; };
.sidebar { position: fixed; width: 250px; height: 100%; left: 0px; top: 0; background: #1b1b1b; font-family: sans-serif; }.menu-bar { background: #1b1b1b; height: 60px; display: flex; align-items: center; padding-left: 42px; }.side-text { color: #c5c5c5; font-weight: bold; font-size: 20px; } nav ul { background: #1b1b1b; height: 100%; width: 100%; list-style: none; margin-left: 0; padding-left: 0; } nav ul li { line-height: 40px; } nav ul li a { position: relative; color: #c5c5c5; text-decoration: none; font-size: 14px; padding-left: 43px; font-weight: normal; display: block; width: 100%; } nav ul ul { position: static; display: none; } nav ul ul li a { font-family: sans-serif; font-size: 13px; color: #e6e6e6; padding-left: 80px; font-weight: lighter; } /*************/ /* ADDED CSS */ /*************/ /* All classes starting with "menu-item" */ [class^="menu-item"] + ul { display: none } /* hide adjacent UL */ [class^="menu-item"]:hover { color: #255daa } /* hover color */ a + ul li a:hover { color: #c5c5c5; background-color: #1b1b1b } /* menu-item adjacent sub-menu-items hover colors Here the generic form is used, but it would probably be more clear to be specific and use: - either.menu-item1:focus + ul li a:hover - or.menu-item2.selected + ul li a:hover */ /* ':focus' version This version uses the CSS ':focus' without any Javascript. Main difference with the '.selected' version below is that when the user clicks outside the '.menu-item', the '.menu-item' looses focus and therefore gets hidden again (as:focus is no longer true). */.menu-item1:focus, .menu-item1:focus + ul { color: #e6e6e6; background-color: #255DAA } /* focus colors */.menu-item1:focus + ul { display: block } /* show adjacent UL */ /* '.selected' version, with Javascript. Basically the same CSS, but now using class '.selected' instead of ':focus'. Closing occurs only on user specific 'click'. */.menu-item2.selected, .menu-item2.selected + ul { color: #e6e6e6; background-color: #255DAA } /* focus colors */.menu-item2.selected + ul { display: block } /* show adjacent UL */ /*********************/ /* for demo use only */ /*********************/ nav h3 { color: rgba(100, 149, 237,.9); /* CornflowerBlue */ font-style: italic; padding-left: 43px; }.anchor { color: white; padding-left: 43px; }.content { font-size: 1.5rem; margin: 5rem 300px; } /* preferred globals */ html,body { box-sizing: border-box; width: 100%; max-width: 100% } *::before,*::after, * { box-sizing: inherit } body { margin: 0 }
<nav class="sidebar"> <div class="menu-bar"> <label class="side-text">MENU</label> </div> <h3>test</h3> <a class="anchor" href="javascript:void(0)">some '.sidebar' <a></a> <ul id="menuList"> <h3>:focus version</h3> <li> <a class="menu-item1" href="javascript:void(0)">Staff</a> <ul> <li><a href="#">New Staff</a></li> <li><a href="#">View Staff</a></li> </ul> </li> <li> <a class="menu-item1" href="javascript:void(0)">Notes</a> <ul> <li><a href="#">New Note</a></li> <li><a href="#">Edit Notes</a></li> </ul> </li> <li> <a class="menu-item1" href="javascript:void(0)">Tasks</a> <ul> <li><a href="#">New Tasks</a></li> <li><a href="#">Edit Task</a></li> </ul> </li> <h3>.selected version</h3> <li> <a class="menu-item2" href="javascript:void(0)">Staff</a> <ul> <li><a href="#">New Staff</a></li> <li><a href="#">View Staff</a></li> </ul> </li> <li> <a class="menu-item2" href="javascript:void(0)">Notes</a> <ul> <li><a href="#">New Note</a></li> <li><a href="#">Edit Notes</a></li> </ul> </li> <li> <a class="menu-item2" href="javascript:void(0)">Tasks</a> <ul> <li><a href="#">New Tasks</a></li> <li><a href="#">Edit Task</a></li> </ul> </li> </ul> </nav> <div class="content"> <h3><b>Note</b></h3> <p> This demo uses two different approaches interchangeably creating a quirky behaviour, which under normal circumstances would not exist. </p> <p>To reproduce:</p> <ul> <li>select a <i>':focus version'</i> menu item first <li>then select a <i>'.selected version'</i> menu item </ul> <p> As you can see, the selected <i>':focus version'</i> loses focus and a second 'click' is needed to activate the <i>'.selected version'</i> menu item. This is because the first click event of the <i>'.selected version'</i> gets consumed by the blur event of the <i>':focus version'</i>. </p> <p>Just so you know...</p> </div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.