setTimeout / clearTimeout问题,似乎没有重置

时间:2014-02-26 08:07:44

标签: javascript jquery settimeout

我正在尝试创建在将鼠标悬停在菜单名称上时下拉菜单。由于名称和菜单div不相邻,我需要一种方法来延迟菜单消失,因此用户可以从名称移动到菜单本身。我为此使用了setTimeout。一旦悬停在菜单上,我需要它保持打开直到鼠标离开,之后它应该隐藏。

我尝试过的是一团糟。不知道如何解决它。因为setTimeout在初始鼠标悬停内,所以定时器会自行循环...但是如果把它放在其他任何地方,setTimeout似乎不起作用。

以下是代码:

$(document).ready(function() {
  $('.headermenushow').mouseover(function () {
    $(this).next('.dropmenu').show(0, function () {
      timer = setTimeout(function() {
        $('.dropmenu').hide(10);
      }, 2000);
    });

    $(this).next('.dropmenu').mouseover(function () {
      clearTimeout(timer);
    });

  });
});

这是一个精简的jsfiddle,显示我想如何使用它:

http://jsfiddle.net/H247x/1/

任何帮助都会很棒。不确定如何让这项工作更好......

1 个答案:

答案 0 :(得分:5)

此代码存在各种问题:

  1. 您正在.mouseover()事件中添加事件处理程序。这意味着每次有鼠标悬停事件时,您都会添加另一组事件处理程序。当ALL执行时,这些将堆积起来并使其变得非常混乱。每个活动对象只需要一组事件处理程序。

  2. 你应该如何运作的整个逻辑似乎存在缺陷。只要鼠标悬停在某个项目上,您就希望菜单保持下拉状态。鼠标悬停事件仅在鼠标首次移动到项目上时发生。当鼠标悬停在菜单上时,你没有任何方法可以保持菜单状态,因为无论鼠标是否仍然存在,你只需在显示后2秒钟盲目隐藏菜单。

  3. 您正在为计时器使用隐式全局变量。这会产生一系列问题。首先,如果有多个.headermenushow对象,则每个对象的timer将踩到其他对象。第二个隐式全局变量很糟糕,很容易导致错误。在你想要的范围内明确地声明它。

  4. 您可以在计时器之上定时器。无论何时将计时器保存到共享变量,都必须检查已经运行的先前计时器或在覆盖其变量之前停止任何先前的计时器。这可以防止丢失正在运行的计时器的跟踪,并防止堆叠多个计时器都试图做同样的事情。

  5. 我们可能会帮助您提供更好的代码,但我们需要查看您的实际HTML并更好地了解您尝试实现的行为。

    仅供参考,您可能还想查看CSS :hover选择器,它可以让您在没有任何JS代码的情况下悬停时显示/隐藏内容。由于我不知道您的HTML是什么样的,我无法确定这是否适合您,但许多菜单系统使用它是非常简单的。如果做得好的话。


    现在您已经发布了HTML,这是一个有效的版本。我必须说很多这样的javascript是因为你的HTML并没有让它变得如此简单。

    $(document).ready(function() {
        $(".headermenushow").hover(function() {
            // hide any previous dropdown menus
            $(".dropmenu").hide();
    
            var self = $(this);
            var timer = self.data("timer");
    
            // show the dropdown menu for this item
            self.next().show();
    
            // clear any previous timer for this menu
            if (timer) {
                clearTimeout(timer);
                self.data("timer", null);
            }
    
        }, function() {
            // hide only on a delay so that user can move
            // to the menu
            var self = $(this);
            var menu = self.next();
            var timer = self.data("timer");
            // clear any previous timer that might have been active
            if (timer) clearTimeout(timer);
            timer = setTimeout(function() {
                self.data("timer", null);
                // if mouse is not over the menu, then hide it
                if (!menu.data("hover")) {
                    menu.hide();
                }
            }, 500);
            self.data("timer", timer);
    
        });
    
        // keep track of hover state on the menu
        $(".dropmenu").hover(function() {
            $(this).data("hover", true);
        }, function() {
            $(this).data("hover", false);
            $(this).hide();
        });
    });
    

    工作演示:http://jsfiddle.net/jfriend00/YJu6Q/