将悬停区域扩展到外部元素

时间:2016-09-21 09:10:12

标签: javascript jquery css javascript-events hover

我有一个下拉菜单,其子菜单放在不同的元素上。所以基本上当鼠标离开菜单项时,子菜单会立即关闭,因为子菜单不是孩子。



var menuItem = $(".menu-item");


menuItem.hover(hoverIn, hoverOut);

function hoverIn() {
  var mnItemMeta = $(this)[0].getBoundingClientRect();

  $(".sub-menu").css({
    opacity: 1,
    left: mnItemMeta.left
  })
}

function hoverOut() {
  $(".sub-menu").css({
    opacity: 0
  })
}

html,body{background-color: #efefef;}
.menu {
  list-style: none;
  padding-left: 0;
  display: flex;
  justify-content: center;
}
a {
  display: block;
  padding: 10px 20px;
  text-decoration: none;
  color: inherit;
}
.sub-menu {
  opacity: 0;
  background-color: white;
  position: absolute;
  transition: .2s ease;
}
.sub-menu-list {
  list-style: none;
  padding-left: 0;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="menu">
  <li class="menu-item"><a href="#">Menu Item</a>
  </li>
</ul>
<div class="sub-menu">
  <ul class="sub-menu-list">
    <li><a href="#">Sub Menu 1</a>
    </li>
    <li><a href="#">Sub Menu 2</a>
    </li>
    <li><a href="#">Sub Menu 3</a>
    </li>
    <li><a href="#">Sub Menu 4</a>
    </li>
  </ul>
</div>
&#13;
&#13;
&#13;

https://jsfiddle.net/yans_fied/6wj0of90/

问题是如何扩展悬停区域,所以当光标指向子菜单时,它会忽略hoverOut操作。

注意:不要告诉我将子菜单放在菜单项中,我已经知道它是如何工作的。对于需要将子菜单放在菜单项之外的不同情况。谢谢:))

6 个答案:

答案 0 :(得分:6)

您可以将sub-menu放入menu-item

&#13;
&#13;
var menuItem = $(".menu-item");
menuItem.hover(hoverIn, hoverOut);

function hoverIn() {
  var mnItemMeta = $(this)[0].getBoundingClientRect();

  $(".sub-menu").css({
    opacity: 1,
    left: mnItemMeta.left
  })
}

function hoverOut() {
  $(".sub-menu").css({
    opacity: 0
  })
}
&#13;
html, body {
  background-color: #efefef;
}
.menu {
  list-style: none;
  padding-left: 0;
  display: flex;
  justify-content: center;
}
a {
  display: block;
  padding: 10px 20px;
  text-decoration: none;
  color: inherit;
}
.sub-menu {
  opacity: 0;
  background-color: white;
  position: absolute;
  transition: .2s ease;
}
.sub-menu-list {
  list-style: none;
  padding-left: 0;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<ul class="menu">
  <li class="menu-item"><a href="#">Menu Item</a>
    <div class="sub-menu">
      <ul class="sub-menu-list">
        <li><a href="#">Sub Menu 1</a></li>
        <li><a href="#">Sub Menu 2</a></li>
        <li><a href="#">Sub Menu 3</a></li>
        <li><a href="#">Sub Menu 4</a></li>
      </ul>
    </div>
  </li>
</ul>
&#13;
&#13;
&#13;

另一种方法是检查hover.menu-item的{​​{1}}状态。你需要在这里使用一点暂停,以防止它提前关闭。

&#13;
&#13;
.sub-menu
&#13;
var timeout,
    hovered = false,
    menuItem = $(".menu-item, .sub-menu").hover(hoverIn, hoverOut);;

function hoverIn() {
    hovered = true;

    var mnItemMeta = this.getBoundingClientRect();

    $(".sub-menu").show().css({
        opacity: 1,
        left: mnItemMeta.left,
    });
}

function hoverOut() {
  hovered = false;

    clearTimeout(timeout);
    timeout = setTimeout(function() {
        if (!hovered) {
            $(".sub-menu").css({
                opacity: 0,
            }).hide()
        }
    }, 100);
}
&#13;
html, body {
  background-color: #efefef;
}
.menu {
  list-style: none;
  padding-left: 0;
  display: flex;
  justify-content: center;
}
a {
  display: block;
  padding: 10px 20px;
  text-decoration: none;
  color: inherit;
}
.sub-menu {
  opacity: 0;
  background-color: white;
  position: absolute;
  transition: .2s ease;
}
.sub-menu-list {
  list-style: none;
  padding-left: 0;
}
&#13;
&#13;
&#13;

答案 1 :(得分:2)

你可以添加

.sub-menu::before{
     content:'';
     height: <height of menu item>
     width: 100%;
     position:absolute;
     bottom:100%;
}

并将hoverOut放在.sub-menu

答案 2 :(得分:2)

以下是

的示例
  1. 将伪元素添加到子菜单以提供悬停的重叠区域。它仅为演示用途的黄色。
  2. 将鼠标悬停在菜单和子菜单之外,只设置一个变量。子菜单隐藏在一个单独的函数中,它会评估变量。需要稍微超时以允许从一个更改为另一个。
  3. &#13;
    &#13;
    var menuItem = $(".menu-item");
    var submenuItem = $(".sub-menu");
    
    var hoverMenu = false;
    var hoverSubmenu = false;
    
    
    menuItem.hover(hoverIn, hoverOut);
    
    function hoverIn() {
      hoverMenu = true;
      var mnItemMeta = $(this)[0].getBoundingClientRect();
    
      $(".sub-menu").css({
        opacity: 1,
        left: mnItemMeta.left
      })
    }
    
    function hoverOut() {
      hoverMenu = false;
      setTimeout (hide, 10);
    }
    
    submenuItem.hover(hoverSmIn, hoverSmOut);
    
    function hoverSmIn() {
      hoverSubmenu = true;
    }
    
    function hoverSmOut() {
      hoverSubmenu = false;
      setTimeout (hide, 10);
    }
    
    function hide() {
      if (hoverMenu == false && hoverSubmenu == false) {
        $(".sub-menu").css({
          opacity: 0
        })
      }
    }
    &#13;
    html,body{background-color: #efefef;}
    .menu {
      list-style: none;
      padding-left: 0;
      display: flex;
      justify-content: center;
    }
    a {
      display: block;
      padding: 10px 20px;
      text-decoration: none;
      color: inherit;
    }
    .sub-menu {
      opacity: 0;
      background-color: white;
      position: absolute;
      transition: .2s ease;
    }
    .sub-menu:before {
      content: "";
      position: absolute;
      width: 100%;
      left: 0px;
      bottom: 100%;
      height: 26px;
      background-color: yellow;
    }
    .sub-menu-list {
      list-style: none;
      padding-left: 0;
    }
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <ul class="menu">
      <li class="menu-item"><a href="#">Menu Item</a>
      </li>
    </ul>
    <div class="sub-menu">
      <ul class="sub-menu-list">
        <li><a href="#">Sub Menu 1</a>
        </li>
        <li><a href="#">Sub Menu 2</a>
        </li>
        <li><a href="#">Sub Menu 3</a>
        </li>
        <li><a href="#">Sub Menu 4</a>
        </li>
      </ul>
    </div>
    &#13;
    &#13;
    &#13;

答案 3 :(得分:2)

我今天在你的剧本上玩了一段时间,从你的Fiddle开始,而不是部分片段......

你是如此接近...... 但问题是你有两个不同的父元素类来处理(读取:事件处理程序绑定到它们)...并处理不同。

当您将鼠标从打开子菜单的元素移动到另一个应该保持打开状态的元素时,不应触发某些事件。仅当鼠标未输入另一个mouseoutmenu___item“快速”时,才会发生dropdown-menu__content事件。

mouseentermouseout在触发器上非常快速 ...比人类鼠标移动更快。

这里有一个小的100ms延迟。

setTimeout()dropdown-holder设置为display:none以保留这些元素,并在进入时clearTimeout

$(".menu__item").hover(
  function() {
    $(".dropdown-holder").css({"display":"block"});
    displaySubMenu( $(this) );
    clearTimeout(NavDelay);
  },
  function(){
    setNavDelay();
  });

$(".dropdown-menu__content").hover(
  function() {
    clearTimeout(NavDelay);
  },
  function(){
    setNavDelay();
  });

setTimout函数很简单:

function setNavDelay(){
  NavDelay = setTimeout(function(){
        $(".dropdown-holder").css({"display":"none"});
    },100);
}

这是子菜单显示功能,没有那么多修改:

function displaySubMenu(element){
  var itemMeta = element[0].getBoundingClientRect();
  //console.log( itemMeta );
  var subID = element.data('sub');
  console.log(subID);

  var subCnt = $(subID).find(".dropdown-menu__content").css({"display":"block"});
  var subMeta = subCnt[0].getBoundingClientRect();
  //console.log( subMeta );
  var subCntBtm = subCnt.find(".bottom-section");

  menuHoveredID = subID;  // Let's Keep this info in memory in a var that has global scope

  $(drBg).css({
    "display":"block",
    "left": itemMeta.left - ((subMeta.width / 2) - itemMeta.width / 2),
    "width": subMeta.width,
    "height": subMeta.height
  });
  $(drBgBtm).css({
    "top": subCntBtm.position().top
  });
  $(drArr).css({
    "display":"block",
    "left": itemMeta.left + itemMeta.width / 2 - 10
  });
  $(drCnt).css({
    "display":"block",
    "left": itemMeta.left - ((subMeta.width / 2) - itemMeta.width / 2),
    "width": subMeta.width,
    "height": subMeta.height
  });

  // Ensure the right content is displayed
  $(".dropdown-menu__content").css({
    "display":"none"
  });
  $(menuHoveredID).find(".dropdown-menu__content").css({
    "display":"block"
  });
}

为确保显示正确的内容,menuHoveredID变量通过mouseenter menu__item的{​​{1}}处理程序进入该功能。

你的onload声明:

hover

我脱掉了这个愚蠢的行为并加了两个变形...... 如果你注意到,我也纠正了分号/昏迷...;)

<强> Working CodePen here

答案 4 :(得分:1)

如果您将第一个js行更改为:.menu,然后将var menuItem = $(".menu-item, .sub-menu"); menuItem.hover(hoverIn, hoverOut); function hoverIn() { var mnItemMeta = $(this)[0].getBoundingClientRect(); $(".sub-menu").css({ opacity: 1, left: mnItemMeta.left }) } function hoverOut() { $(".sub-menu").css({ opacity: 0 }) }添加到html,body{background-color: #efefef;} .menu { list-style: none; padding-left: 0; display: flex; justify-content: center; } a { display: block; padding: 10px 20px; text-decoration: none; color: inherit; } .sub-menu { opacity: 0; background-color: white; position: absolute; transition: .2s ease; top: 3em; } .sub-menu-list { list-style: none; padding-left: 0; } css(以提供与<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <ul class="menu"> <li class="menu-item"><a href="#">Menu Item</a> </li> </ul> <div class="sub-menu"> <ul class="sub-menu-list"> <li><a href="#">Sub Menu 1</a> </li> <li><a href="#">Sub Menu 2</a> </li> <li><a href="#">Sub Menu 3</a> </li> <li><a href="#">Sub Menu 4</a> </li> </ul> </div> div的微小重叠并删除闪烁)那么一切都应该是好的。

&#13;
&#13;
{{1}}
&#13;
{{1}}
&#13;
{{1}}
&#13;
&#13;
&#13;

答案 5 :(得分:-3)

好的,我已经找到了解决方案。感谢各位提供一些建议,但我不能接受你们的答案,因为解决方案需要更多的解决方法。

所以,基本上我创建了两个函数,startCloseTimeout()stopCloseTimout(),并将它绑定在menu-itemsubmenu上。

这是函数本身:

var startCloseTimeout = function (){
    closeDropdownTimeout = setTimeout( () => closeDropdown() , 50 );
},

stopCloseTimeout   = function () {
    clearTimeout( closeDropdownTimeout );
};

以下是我如何绑定鼠标事件:

//- Binding mouse event to each menu items
menuItems.forEach( el => {

    //- mouse enter event
    el.addEventListener( 'mouseenter', function() {
        stopCloseTimeout();
        openDropdown( this );
    }, false );

    //- mouse leave event
    el.addEventListener( 'mouseleave', () => startCloseTimeout(), false);

} );

//- Binding mouse event to each sub menus
menuSubs.forEach( el => {

    el.addEventListener( 'mouseenter', () => stopCloseTimeout(), false );
    el.addEventListener( 'mouseleave', () => startCloseTimeout(), false );

} );

那么,这段代码是如何工作的?

通过创建关闭超时处理程序,我们可以控制下拉列表何时关闭。

当鼠标进入菜单项时,会发生以下情况: 1.停止当前运行closeDropdownTimout 2.打开相关的下拉菜单

当鼠标离开菜单项时,它会启动closeDropdownTimout

但下拉菜单仍然如何打开?由于我们在下拉菜单中设置了相同的操作,因此可以清除closeDropdownTimout并取消关闭操作。

有关完整源代码,您可以在codepen http://codepen.io/ariona/pen/pENkXW

上查看

感谢。