如何使用JavaScript中的悬停事件遍历大型菜单?

时间:2022-06-06 11:46:10

I am building a mega menu style navigation using HTML, CSS, and JavaScript. See code pen here. http://codepen.io/anon/pen/bZoBYz

我正在使用HTML,CSS和JavaScript构建一个超级菜单样式导航。请在此处查看代码笔。 http://codepen.io/anon/pen/bZoBYz

HTML:

<div id="menu">
      <div id="menu-wrapper">
        <ul>
          <li><a id="item-1-button" href="#">Item 1</a></li><li><a href="#">Item 2</a></li><li><a href="#">Item 3</a></li>
        </ul>
      </div>
    </div>

    <div id="mega-menu">
      <div id="mega-menu-wrapper">
        <div id="item-1-menu">
          <ul>
            <li>Child list item 1</li>
            <li>Child list item 2</li>
            <li>Child list item 3</li>
          </ul>
        </div>
      </div>
    <div>

CSS:

* {
  margin: 0px;
  padding: 0px;
  border: none;
  outline: none;
  font-family: sans-serif;
}

div#menu {
  position: relative;
  background: #DDD;
  overflow: hidden;
  height: 50px;
}

div#menu ul{
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

div#menu ul li {
  display: inline-block;
}

div#menu ul li a {
  text-decoration: none;
  padding: 20px;
  background: #AAA;
}

div#menu-wrapper {
  width: 900px;
  margin: auto;
}

div#mega-menu {
  height: 200px;
  position: relative;
  background: #AAA;
  display: none;
}

div#mega-menu-wrapper {
  width: 900px;
  height: 100px;
  margin: auto;
}

div#item-1-menu {
  position: absolute;
  display: none;
  padding: 20px;
}

div#item-1-menu ul li {
  list-style: none;
}

JavaScript:

var itemOneButton = document.getElementById("item-1-button");
var itemOneMenu = document.getElementById("item-1-menu");
var megaMenu = document.getElementById("mega-menu");

var hoveringItemOne = false;
var hoveringMegaMenu = false;

itemOneButton.addEventListener('mouseover', function() {
  hoveringItemOne = true;
  changeMenu("item1");
}, true);

itemOneButton.addEventListener('mouseout', function() {
  hoveringItemOne = false;
  changeMenu();
}, true);

megaMenu.addEventListener('mouseover', function() {
  hoveringMegaMenu = true;
  changeMenu();
}, true);

megaMenu.addEventListener('mouseout', function() {
  hoveringMegaMenu = false;
  changeMenu();
}, true);

function changeMenu(menuItem) {
  if(menuItem === "item1") {
    showItem1Menu()
  }

  if(hoveringItemOne == false && hoveringMegaMenu == false) {
    hideItem1Menu();
  }
}

function showItem1Menu() {
  megaMenu.style.display = 'block';
  itemOneMenu.style.display = 'block';
}

function hideItem1Menu() {
  megaMenu.style.display = 'none';
  itemOneMenu.style.display = 'none';
}

If you hover Item 1 in the menu, the mega menu for that menu item will appear. The problem is that when I try to hover from the menu item down to the mega menu, it will disappear even though the two are right beside each other.

如果您将菜单中的项目1悬停,则会显示该菜单项的超级菜单。问题是当我尝试从菜单项向下悬停到大型菜单时,即使两者正好在彼此旁边,它也会消失。

Im using boolean variables to control the visibility of the mega menu because I eventually want to have the menu work from item 1, 2, 3, or more menu items.

我使用布尔变量来控制大型菜单的可见性,因为我最终希望菜单可以使用第1,2,3或更多菜单项。

I have also tried this variation where I set both of the following variables to true when hovering the first menu item. - hoveringItemOne - hoveringMegaMenu http://codepen.io/anon/pen/oLGYOE

我也尝试过这种变化,当我将鼠标悬停在第一个菜单项时,我将以下两个变量都设置为true。 - hoveringItemOne - hoveringMegaMenu http://codepen.io/anon/pen/oLGYOE

itemOneButton.addEventListener('mouseover', function() {
  hoveringItemOne = true;
  hoveringMegaMenu = true;
  changeMenu("item1");
}, true);

A problem with this variation is that the hover value of the variable hoveringMegaMenu variable is disturbed by its child elements. It also stays true forever if the mega menu that appears is never touched.

这种变化的一个问题是变量hoveringMegaMenu变量的悬停值受其子元素的干扰。如果永远不会触及出现的巨型菜单,它也会永远保持真实。

Is there a better way of developing a mega menu like this? The point is to be able to interact with anything inside the mega menu continaer until the cursor leaves either the mega menu spanning the entire width of the page, or until another menu item is hovered, which would reveal a new set of content.

有没有更好的方法来开发像这样的大型菜单?关键是能够与超级菜单控制器内的任何内容进行交互,直到光标离开页面的整个宽度的大型菜单,或者直到另一个菜单项被悬停,这将显示一组新的内容。

2 个解决方案

#1


0  

Try to use like this

尝试使用这样的

var itemOneButton = document.getElementById("item-1-button");
var itemOneMenu = document.getElementById("item-1-menu");
var megaMenu = document.getElementById("mega-menu");

var hoveringItemOne = false;

itemOneButton.addEventListener('mouseover', function() {
  hoveringItemOne = true;
});
itemOneButton.addEventListener('mouseout', function() {
  hoveringItemOne = false;
});
megaMenu.addEventListener('mouseover', function() {
  hoveringItemOne = true;
});
megaMenu.addEventListener('mouseout', function() {
  hoveringItemOne = false;
});

document.addEventListener('mousemove', function() {
  if (hoveringItemOne) {
    megaMenu.style.display = "block";
    itemOneMenu.style.display = "block";
  } else {
    megaMenu.style.display = "none";
    itemOneMenu.style.display = "none";
  }
});
* {
  margin: 0px;
  padding: 0px;
  border: none;
  outline: none;
  font-family: sans-serif;
}

div#menu {
  position: relative;
  background: #DDD;
  overflow: hidden;
  height: 50px;
}

div#menu ul {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

div#menu ul li {
  display: inline-block;
}

div#menu ul li a {
  text-decoration: none;
  padding: 20px;
  background: #AAA;
}

div#menu-wrapper {
  width: 900px;
  margin: auto;
}

div#mega-menu {
  height: 200px;
  position: relative;
  background: #AAA;
  display: none;
}

div#mega-menu-wrapper {
  width: 900px;
  height: 100px;
  margin: auto;
}

div#item-1-menu {
  position: absolute;
  display: none;
  padding: 20px;
}

div#item-1-menu ul li {
  list-style: none;
}
<div id="menu">
  <div id="menu-wrapper">
    <ul>
      <li><a id="item-1-button" href="#">Item 1</a></li>
      <li><a href="#">Item 2</a></li>
      <li><a href="#">Item 3</a></li>
    </ul>
  </div>
</div>

<div id="mega-menu">
  <div id="mega-menu-wrapper">
    <div id="item-1-menu">
      <ul>
        <li>Child list item 1</li>
        <li>Child list item 2</li>
        <li>Child list item 3</li>
      </ul>
    </div>
  </div>
  <div>

Here is the jsFiddle

这是jsFiddle

Hope it helps :)

希望能帮助到你 :)

#2


0  

I may be missing something, but It seems like you can get away with a bit less code - and maybe even leave out the JavaScript. Check out this codePen: http://codepen.io/sheriffderek/pen/XKZpJR?editors=0100

我可能会遗漏一些东西,但似乎你可以用更少的代码逃脱 - 甚至可能省略JavaScript。看看这个代码图:http://codepen.io/sheriffderek/pen/XKZpJR?editors = 0100

There are times where the sub-menus need to be separate, (in which case you would need to watch interaction with JavaScript) - but you can often put them each in their list-item parent and use the wonderful position: relative; and position: absolute; relational positioning.

有时候子菜单需要分开,(在这种情况下你需要观察与JavaScript的交互) - 但你经常可以将它们放在list-item父项中并使用奇妙的位置:relative;和位置:绝对;关系定位。

markup

<ul class='menu'>

    <li>
        <a href="">Dirt Nap</a>
        <ul class='sub-menu'>
            <li><a href="">Heart Felt</a></li>
            <li><a href="">Moon Belt</a></li>
            <li><a href="">Belted out</a></li>
            <li><a href="">Outgoing</a></li>
            <li><a href="">Closet Deserter</a></li>
        </ul>
    </li>

    ...


styles

(you can turn them to CSS in the codepen)

(你可以把它们转换成codepen中的CSS)

ul
    list-style: none
    margin: 0
    padding: 0

.big-ugly-monstrosity
    width: 100%
    float: left
    background: $color
    .menu
        position: relative
        width: 100%
        float: left // should be clear-fix
        a //
            display: block
            padding: $pad
            &:hover
                background: rgba(0,0,0,.1)
        li
            float: left
        > li
            //
            &:hover
                .sub-menu
                    display: block
            &:nth-of-type(2n +2)
                .sub-menu // to show stacked sub-menu items...
                    li //
                        width: 100%
    .sub-menu
        display: none
        position: absolute
        top: 100%
        left: 0
        width: 100%
        background: $highlight

I would encourage you to do something like this instead though: http://codepen.io/sheriffderek/pen/lEghe

我会鼓励你做这样的事情:http://codepen.io/sheriffderek/pen/lEghe

I think that hover/ drop-down menus are a pretty lousy user-interface now that we have touch screens and such varied devices.

我认为悬停/下拉菜单是一个非常糟糕的用户界面,现在我们有触摸屏和各种各样的设备。

If you do go with JavaScript, you can associate the 'tabs' and their sub-menus with rel='tab1' or data-tab='1' and get the data-attr on hover and use it to show the data-sub='1' that it's associated with.

如果你使用JavaScript,你可以将'tabs'及其子菜单与rel ='tab1'或data-tab ='1'相关联,并在悬停时获取data-attr并使用它来显示data-sub ='1'与之相关。

#1


0  

Try to use like this

尝试使用这样的

var itemOneButton = document.getElementById("item-1-button");
var itemOneMenu = document.getElementById("item-1-menu");
var megaMenu = document.getElementById("mega-menu");

var hoveringItemOne = false;

itemOneButton.addEventListener('mouseover', function() {
  hoveringItemOne = true;
});
itemOneButton.addEventListener('mouseout', function() {
  hoveringItemOne = false;
});
megaMenu.addEventListener('mouseover', function() {
  hoveringItemOne = true;
});
megaMenu.addEventListener('mouseout', function() {
  hoveringItemOne = false;
});

document.addEventListener('mousemove', function() {
  if (hoveringItemOne) {
    megaMenu.style.display = "block";
    itemOneMenu.style.display = "block";
  } else {
    megaMenu.style.display = "none";
    itemOneMenu.style.display = "none";
  }
});
* {
  margin: 0px;
  padding: 0px;
  border: none;
  outline: none;
  font-family: sans-serif;
}

div#menu {
  position: relative;
  background: #DDD;
  overflow: hidden;
  height: 50px;
}

div#menu ul {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

div#menu ul li {
  display: inline-block;
}

div#menu ul li a {
  text-decoration: none;
  padding: 20px;
  background: #AAA;
}

div#menu-wrapper {
  width: 900px;
  margin: auto;
}

div#mega-menu {
  height: 200px;
  position: relative;
  background: #AAA;
  display: none;
}

div#mega-menu-wrapper {
  width: 900px;
  height: 100px;
  margin: auto;
}

div#item-1-menu {
  position: absolute;
  display: none;
  padding: 20px;
}

div#item-1-menu ul li {
  list-style: none;
}
<div id="menu">
  <div id="menu-wrapper">
    <ul>
      <li><a id="item-1-button" href="#">Item 1</a></li>
      <li><a href="#">Item 2</a></li>
      <li><a href="#">Item 3</a></li>
    </ul>
  </div>
</div>

<div id="mega-menu">
  <div id="mega-menu-wrapper">
    <div id="item-1-menu">
      <ul>
        <li>Child list item 1</li>
        <li>Child list item 2</li>
        <li>Child list item 3</li>
      </ul>
    </div>
  </div>
  <div>

Here is the jsFiddle

这是jsFiddle

Hope it helps :)

希望能帮助到你 :)

#2


0  

I may be missing something, but It seems like you can get away with a bit less code - and maybe even leave out the JavaScript. Check out this codePen: http://codepen.io/sheriffderek/pen/XKZpJR?editors=0100

我可能会遗漏一些东西,但似乎你可以用更少的代码逃脱 - 甚至可能省略JavaScript。看看这个代码图:http://codepen.io/sheriffderek/pen/XKZpJR?editors = 0100

There are times where the sub-menus need to be separate, (in which case you would need to watch interaction with JavaScript) - but you can often put them each in their list-item parent and use the wonderful position: relative; and position: absolute; relational positioning.

有时候子菜单需要分开,(在这种情况下你需要观察与JavaScript的交互) - 但你经常可以将它们放在list-item父项中并使用奇妙的位置:relative;和位置:绝对;关系定位。

markup

<ul class='menu'>

    <li>
        <a href="">Dirt Nap</a>
        <ul class='sub-menu'>
            <li><a href="">Heart Felt</a></li>
            <li><a href="">Moon Belt</a></li>
            <li><a href="">Belted out</a></li>
            <li><a href="">Outgoing</a></li>
            <li><a href="">Closet Deserter</a></li>
        </ul>
    </li>

    ...


styles

(you can turn them to CSS in the codepen)

(你可以把它们转换成codepen中的CSS)

ul
    list-style: none
    margin: 0
    padding: 0

.big-ugly-monstrosity
    width: 100%
    float: left
    background: $color
    .menu
        position: relative
        width: 100%
        float: left // should be clear-fix
        a //
            display: block
            padding: $pad
            &:hover
                background: rgba(0,0,0,.1)
        li
            float: left
        > li
            //
            &:hover
                .sub-menu
                    display: block
            &:nth-of-type(2n +2)
                .sub-menu // to show stacked sub-menu items...
                    li //
                        width: 100%
    .sub-menu
        display: none
        position: absolute
        top: 100%
        left: 0
        width: 100%
        background: $highlight

I would encourage you to do something like this instead though: http://codepen.io/sheriffderek/pen/lEghe

我会鼓励你做这样的事情:http://codepen.io/sheriffderek/pen/lEghe

I think that hover/ drop-down menus are a pretty lousy user-interface now that we have touch screens and such varied devices.

我认为悬停/下拉菜单是一个非常糟糕的用户界面,现在我们有触摸屏和各种各样的设备。

If you do go with JavaScript, you can associate the 'tabs' and their sub-menus with rel='tab1' or data-tab='1' and get the data-attr on hover and use it to show the data-sub='1' that it's associated with.

如果你使用JavaScript,你可以将'tabs'及其子菜单与rel ='tab1'或data-tab ='1'相关联,并在悬停时获取data-attr并使用它来显示data-sub ='1'与之相关。