-2

我在为每个单独的列表项实现下拉菜单时遇到了困难/悬停在其中任何一个上,现在悬停在任何单个列表项上时,所有下拉菜单都会显示。

这是我的笔: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();
    }
  }
}
4

2 回答 2

0

谢谢您的帮助。已更改代码,对于 showMenu 和 hideMenu 以及 mouseover 和 mouseout 事件,现在单个下拉菜单显示在悬停在单个菜单项上,但下拉菜单很快就会隐藏,我到达下拉菜单中的最后一个菜单项。我是否遗漏了任何东西,目前,只要将鼠标悬停在下拉菜单中的最后一个菜单项上,此错误就会出现在控制台中-

未捕获的类型错误:无法在 main.js:38 处的 hideMenu (main.js:68) 处读取 null 的属性“setAttribute”

    //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();
        }
    }
}
于 2020-09-04T11:54:50.423 回答
0

而不是在悬停时立即打开所有下拉列表,您需要将“悬停”事件传递给函数,以便知道哪个触发器被悬停:

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;
}
于 2020-09-04T11:10:21.257 回答