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

标签 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. 您正在 .mouseover() 事件中添加事件处理程序。这意味着每次发生鼠标悬停事件时,您都会添加另一组事件处理程序。当 ALL 执行时,这些会堆积起来并造成真正的困惑。对于每个事件对象,您只需要一组事件处理程序。

  2. 您的整个逻辑似乎有缺陷。您希望只要鼠标悬停在某个项目上,菜单就保持下拉状态。仅当鼠标首次移动到某个项目上时才会发生 mouseover 事件。当鼠标悬停在菜单上时,您没有任何方法可以保持菜单处于按下状态,因为无论鼠标是否仍然存在,您似乎都会在显示后 2 秒内盲目地将其隐藏。

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

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

我们或许可以帮助您编写更好的代码,但我们需要查看您的实际 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/

关于javascript - setTimeout/clearTimeout 问题,似乎没有重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22035310/

相关文章:

javascript - 如何设置 Origin 请求 header

jquery - 使用 jQuery .load() 时如何更改光标以等待

javascript - body onload setTimeout 无引用

javascript - 将文本传递给 onclick 函数

java - 使用 Jersey 和 JQuery 发布

javascript - 两个 Javascript 函数一个 window.onload = Custom.init;和一个 window.onload = function() {

javascript - 如果父事件已经运行超过一段时间,如何运行函数

javascript - Promise settimeout 最佳实践中的解析 'function' 是什么?

javascript - 将 CSS 链接到 Nodejs 服务器的 HTML

javascript - 如何将图像固定在中心?