jQuery .hover()和$(window).resize()的怪异行为

时间:2018-12-22 13:43:12

标签: jquery css css3

我想做什么:

我的网站上有一个导航栏。一些导航链接具有与之关联的子菜单。我希望能够将鼠标悬停在具有子菜单并显示子菜单的导航链接上。

但是,我希望子菜单根据窗口大小而有所不同:

  • 如果窗口的宽度大于或等于960px,则我的导航栏为水平。我希望子菜单显示为页面其他内容上方的下拉菜单。

  • 如果窗口的宽度小于960px,则我的导航栏为垂直。我希望子菜单显示为手风琴,向下推其他导航链接。

我也希望脚本在页面加载完成并调整窗口大小时执行。

我的脚本:

function navMenu() {
  if ($(window).width() >= 960) {
    $('.menu-item-has-children').hover(function() {
      $(this).children(".sub-menu").css('display', 'block');
    }, function() {
      $(this).children(".sub-menu").css('display', 'none');
    });
  } else {
    $('.menu-item-has-children').hover(function() {
        $(this).children(".sub-menu").slideToggle(500);
      }, function() {
        $(this).children(".sub-menu").slideUp(500);
    });
  }
}
$(document).ready(function() {
   navMenu();
});
$(window).resize(function() {
   navMenu();
});

会发生什么:

$(document).ready()触发时,上述脚本可以正常工作。

问题出在这里:如果在加载窗口后调整窗口大小,该脚本将创建多个mouseovermouseout事件侦听器。将鼠标悬停在导航链接上会导致子菜单反复上下反弹。

您可以在这里看到我的意思:https://codepen.io/ben393/pen/qLrMmX

我已经尝试过(到目前为止还没有成功)的某些事情:

  • 使.hover()具有($(window).width() >= 960)的功能

  • 使$(document).ready()具有$(window).resize()的功能

有什么想法吗?谢谢!

3 个答案:

答案 0 :(得分:1)

正如您提到的,问题在于您每次调整大小时都会继续监听hover事件。解决此问题的一种简单方法是每次使用以下方法取消绑定相应的DOM事件:

$('.menu-item-has-children').off('mouseenter mouseleave');

请注意,hover()在后​​台绑定这两个事件。另请注意,这将删除这些事件的 all 自定义处理程序。您还可以将处理程序函数存储到变量中,如果您想更具体一些,则仅取消绑定它们。

演示(点击“扩展代码段”以全屏对其进行测试):

function navMenu() {
  $('.menu-item-has-children').off('mouseenter mouseleave');
  if ($(window).width() >= 960) {
    $('.menu-item-has-children').hover(function() {
      $(this).children(".sub-menu").css('display', 'block');
    }, function() {
      $(this).children(".sub-menu").css('display', 'none');
    });
  } else {
    $('.menu-item-has-children').hover(function() {
      $(this).children(".sub-menu").slideToggle(500);
    }, function() {
      $(this).children(".sub-menu").slideUp(500);
    });
  }
}
$(document).ready(function() {
  navMenu();
});
$(window).resize(function() {
  navMenu();
});
ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  font-weight: bold;
}

ul li {
  display: inline-block;
  padding: 10px;
  background-color: grey;
}

ul.sub-menu {
  display: none;
  font-weight: normal;
  position: absolute;
}

ul.sub-menu li {
  display: block;
}

@media only screen and (max-width: 959px) {
  ul li {
    display: block;
    width: 100px;
  }
  ul.sub-menu {
    position: relative;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="main_header_menu">
  <li class="menu-item-has-children">Main item 1
    <ul class="sub-menu">
      <li>sub item 1</li>
      <li>sub item 2</li>
      <li>sub item 3</li>
    </ul>
  </li>
  <li>Main item 2</li>
  <li class="menu-item-has-children">Main item 3
    <ul class="sub-menu">
      <li>sub item 1</li>
      <li>sub item 2</li>
      <li>sub item 3</li>
    </ul>
  </li>
</ul>

答案 1 :(得分:0)

将所有内容放到hover()内,您将获得一个更简单,更逻辑的代码,因为您仅定义一次悬停事件。您还可以依靠toggle类来定义一个与mouseentermouseleave

相同的函数
$(document).ready(function() {
  $('.menu-item-has-children').hover(function() {
    if ($(window).width() >= 960) {
      $(this).children(".sub-menu").toggleClass('show');
    } else {
      $(this).children(".sub-menu").slideToggle(500);
    }
  });
});

完整代码:

$(document).ready(function() {
  $('.menu-item-has-children').hover(function() {
    if ($(window).width() >= 960) {
      $(this).children(".sub-menu").toggleClass('show');
    } else {
      $(this).children(".sub-menu").slideToggle(500);
    }
  });
});
ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  font-weight: bold;
}
ul li {
  display: inline-block;
  padding: 10px;
  background-color: grey;
}
ul.sub-menu {
  display: none;
  font-weight: normal;
  position: absolute;
}
ul.sub-menu.show {
 display: block;
}
ul.sub-menu li {
  display: block;
}
@media only screen and (max-width: 959px) {
  ul li {
    display: block;
    width: 100px;
  }
  ul.sub-menu {
    position: relative;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="main_header_menu">
  <li class="menu-item-has-children">Main item 1
    <ul class="sub-menu">
      <li>sub item 1</li>
      <li>sub item 2</li>
      <li>sub item 3</li>
    </ul>
  </li>
  <li>Main item 2</li>
  <li class="menu-item-has-children">Main item 3
    <ul class="sub-menu">
      <li>sub item 1</li>
      <li>sub item 2</li>
      <li>sub item 3</li>
    </ul>
  </li>
</ul>

答案 2 :(得分:0)

如果您将调整大小调用更改为此,那么它将起作用:

$(document).resize(function() { navMenu(); });

此外,您还应该将所有JS包装在$(document).ready()