问题描述
在为每个单独的列表项实现下拉菜单时,我陷入了困境,将焦点悬停在任何一个列表项上,现在将鼠标悬停在任何单个列表项上时,所有下拉菜单都将显示。
这是我的笔:https://codepen.io/apeandme/pen/GRZOxJQ
和JS:
// main navigation interaction
'use strict';
var navbar;
var triggerContainer;
var triggerLink;
var toggleButton;
var lastMenuItem;
var mouSEOutTimer; // timer used to delay hiding of menu after mouse leaves
var mouSEOutHideDelay = 0; // time (in ms) before menu is closed after mouse leaves
var menuVisible = false;
var i = 0;
window.addEventListener('DOMContentLoaded',function(e) {
navbar = document.querySelector('nav');
triggerContainer = document.querySelectorAll('nav > ul > li.with-dd');
triggerLink = document.querySelectorAll('nav > ul > li.with-dd > a');
toggleButton = document.querySelectorAll('nav > ul > li.with-dd > .toggle-button');
lastMenuItem = document.querySelectorAll('nav > ul > li.with-dd > ul > li:last-of-type > a');
// Show the menu on mouse hover of the trigger
triggerContainer.forEach(item => {
item.addEventListener('mouSEOver',function(e) {
showMenu();
clearTimeout(mouSEOutTimer);
});
});
// Hide the menu when mouse hover leaves both the trigger and menu fly-out,but only after a short delay to help people jerky mouse movements (like those using head/eye trackers)
triggerContainer.forEach(item => {
item.addEventListener('mouSEOut',function(e) {
mouSEOutTimer = setTimeout(function() {
hideMenu();
},mouSEOutHideDelay);
});
});
// Hide the menu when the user tabs out of it
triggerContainer.forEach(item => {
item.addEventListener('keydown',triggerKeydownHandler);
});
// Toggle the menu when the trigger is activated
toggleButton.forEach(item => {
item.addEventListener('click',toggleMenu);
});
// Close the menu when the user activates something outside the navbar.
document.body.addEventListener('click',handleBodyClick);
});
/**
Menu visibility
**/
function showMenu() {
triggerLink.forEach(item => {
item.setAttribute('aria-expanded',true);
});
toggleButton.forEach(item => {
item.setAttribute('aria-expanded',true);
});
menuVisible = true;
}
function hideMenu() {
triggerLink.forEach(item => {
item.setAttribute('aria-expanded',false);
});
toggleButton.forEach(item => {
item.setAttribute('aria-expanded',false);
});
menuVisible = false;
}
function toggleMenu() {
if (menuVisible) {
hideMenu();
} else {
showMenu();
}
}
/**
Event handlers
*/
function handleBodyClick(e) {
if (!navbar.contains(e.target)) {
hideMenu();
}
}
function triggerKeydownHandler(e) {
// Hide the menu a keyboard user tabs out of it or presses Escape
if ((e.key === 'Tab' && !e.shiftKey && e.target === lastMenuItem) || e.key == 'Escape') {
hideMenu();
// Move focus back to the menu toggle button if Escape was pressed
if (e.key == 'Escape') {
toggleButton.focus();
}
}
}
解决方法
您需要将'hover'事件传递给函数,而不是立即悬停所有的下拉列表,以便知道哪些触发器已被悬停:
triggerContainer.forEach((item) => {
item.addEventListener("mouseover",function (event) { // catch the 'hover' event
showMenu(event); // pass the event to your function
clearTimeout(mouseOutTimer);
});
});
function showMenu(event) {
event.target.setAttribute("aria-expanded",true); // know which element whas hovered
event.target.nextElementSibling.setAttribute("aria-expanded",true); // open the corresponding dropdown
menuVisible = true;
}
,
感谢您的帮助。已经更改了showMenu和hideMenu的代码,以及mouseover和mouseout事件的代码,现在将单个下拉菜单悬停在单个菜单项上时会显示下拉菜单,但是只要我够到下拉菜单中的最后一个菜单项,这些下拉菜单就会隐藏起来。我是否缺少任何内容,并且现在将鼠标悬停在下拉菜单中的最后一个菜单项上时,控制台中就会出现此错误-
未捕获的TypeError:无法读取null的属性“ setAttribute” 在hideMenu(main.js:68) 在main.js:38
//main navigation interaction
"use strict";
var navbar;
var triggerContainer;
var triggerLink;
var toggleButton;
var lastMenuItem;
var mouseOutTimer; // timer used to delay hiding of menu after mouse leaves
var mouseOutHideDelay = 1000; // time (in ms) before menu is closed after mouse leaves
var menuVisible = false;
window.addEventListener("DOMContentLoaded",function (e) {
navbar = document.querySelector("nav");
triggerContainer = document.querySelectorAll("nav > ul > li.with-dd");
triggerLink = document.querySelectorAll("nav > ul > li.with-dd > a");
toggleButton = document.querySelectorAll(
"nav > ul > li.with-dd > .toggle-button"
);
lastMenuItem = document.querySelectorAll(
"nav > ul > li.with-dd > ul > li:last-of-type > a"
);
// Show the menu on mouse hover of the trigger
triggerContainer.forEach((item) => {
item.addEventListener("mouseover",function (e) {
showMenu(e);
clearTimeout(mouseOutTimer);
});
});
// Hide the menu when mouse hover leaves both the trigger and menu fly-out,but only after a short delay to help people jerky mouse movements (like those using head/eye trackers)
triggerContainer.forEach((item) => {
item.addEventListener("mouseout",function (e) {
mouseOutTimer = setTimeout(function () {
hideMenu(e);
},mouseOutHideDelay);
});
});
// Hide the menu when the user tabs out of it
triggerContainer.forEach((item) => {
item.addEventListener("keydown",triggerKeydownHandler);
});
// Toggle the menu when the trigger is activated
toggleButton.forEach((item) => {
item.addEventListener("click",toggleMenu);
});
// Close the menu when the user activates something outside the navbar.
document.body.addEventListener("click",handleBodyClick);
});
/**
Menu visibility
**/
function showMenu(e) {
e.target.setAttribute("aria-expanded",true);
e.target.nextElementSibling.setAttribute("aria-expanded",true);
menuVisible = true;
}
function hideMenu(e) {
e.target.setAttribute("aria-expanded",false);
e.target.nextElementSibling.setAttribute("aria-expanded",false);
menuVisible = false;
}
function toggleMenu() {
if (menuVisible) {
hideMenu(e);
} else {
showMenu(e);
}
}
/**
Event handlers
*/
function handleBodyClick(e) {
if (!navbar.contains(e.target)) {
hideMenu();
}
}
function triggerKeydownHandler(e) {
// Hide the menu a keyboard user tabs out of it or presses Escape
if (
(e.key === "Tab" && !e.shiftKey && e.target === lastMenuItem) ||
e.key == "Escape"
) {
hideMenu();
// Move focus back to the menu toggle button if Escape was pressed
if (e.key == "Escape") {
toggleButton.focus();
}
}
}