setTimeout()和设置参数

我有一些看起来像这样的jQuery代码:

$('.mainNav2 > li').mouseleave(function(){ var someNum = Math.random(); $(this).attr('id', someNum); var t = setTimeout("HideMenu(someNum)", 200); $('li.clicked').mouseenter(function() { clearTimeout(t); }); }); function HideMenu(id) { $('#'+id).removeClass('clicked'); } 

它的目的是在鼠标离开时隐藏一个巨大的菜单,但也考虑到意外的鼠标离开,使用300毫秒setTimeout。 如果用户在300毫秒内将鼠标指针返回到li,则不会隐藏菜单,因为调用了clearTimout(t)。

问题是当用户意图捕鼠时,没有调用setTimout中的函数。 根据这个页面: http : //www.w3schools.com/js/js_timing.asp我的语法是正确的,但我只能从setTimeout中调用HideMenu函数,如果我这样写:

 var t = setTimeout(HideMenu, 300); 

为什么它不能像写入一样工作,我可以将变量作为参数传递给函数?

虽然明确正确的答案是实现这一目标的一种方法……我不相信这是正确的。

请参阅随附的JS小提琴: http : //jsfiddle.net/PWHw3/

我们在这里做的主要是:

 setTimeout(function, timeout, param); 

例:

 var test = function(a){ var b = (a) ? a : "fail"; alert(b); }; setTimeout(test, 500, "works"); 

这对我有用,并且消除了通过两个function的需要。

为了使它工作,并且不使用令人讨厌的eval版本的setTimeout更改:

 var t = setTimeout("HideMenu(someNum)", 200); 

对此:

 var t = setTimeout(function(s) { return function() { HideMenu(s) } }(someNum), 200); 

这样就可以将someNum的值传递给setTimeout范围内的变量s

setTimeout接受函数和毫秒延迟。 该函数可以是函数引用,也可以是在超时触发时进行评估的字符串。 您当前的序列如下所示:

  • mouseleavefunction

    • 为变量someNum赋值。 someNum的范围限定为当前函数
    • 设置一个计时器,在200ms后评估字符串"HideNum(someNum)"
    • 结束function,保留function范围
  • 200ms通过

  • 评估"HideNum(someNum)" 。 它应该抛出一个exception,因为变量some​​Num是未定义的。 这就是为什么不调用HideNum的原因 – 检查控制台中的错误。

你想要的是一个函数引用,它将使你的someNum保持在范围内(通过闭包 – 你可能想要阅读它)。

 setTimeout(function() { HideNum(someNum); }, 200); 

您会发现Mozilla文档是JavaScript的更好参考。 这是window.setTimeout文档。

你想要做的是创建一个匿名函数并在setTimeout调用中调用它。

 setTimeout(function() { HideMenu(someNum) }, 200); 

但是,如果我正确理解你想要做什么,你就不必费心去设置id和所有这些东西。 这样的事情应该这样做:

 $('.mainNav2 > li').mouseleave(function() { var $this = $(this); var t = setTimeout(function() { $this.removeClass('clicked'); }, 200); $('li.clicked').mouseenter(function() { clearTimeout(t); }); }); 

还有更多方法可以做到这一点。

1.使用匿名function(推荐)

 setTimeout(function() { hideMenu('someNum'); }, 200); 

2. setTimeoutsetInterval具有隐藏function:您可以在超时后指定参数。

 setTimeout(hideMenu, 200, params); 

既然你已经在使用jQuery了,你不应该创建一个单独的函数,而是扩展jQuery的原型,如下所示:

 jQuery.fn.hideMenu = function() { this.removeClass('clicked'); return this; }; 

用法:

 $('#num').hideMenu(); 

请注意,当您扩展其原型时,您不需要将其传递给jQuery,因为它已经传递给jQuery。 并return this; 要求保持链接的能力。

如果你选择这种方式,你需要使用匿名函数,没有更简单的方法。


更新

已有一个插件: jQuery.hoverIntent() 。 无需亲自制作。 它易于使用,只需将mouseleave事件替换为:

 $('#someNum').hoverIntent(jQuery.noop, function() { // your function goes here }); 

这样做非常重要,因为第一个是mouseenter处理程序,第二个是mouseleave处理程序。 jQuery.noop是一个空函数,它实际上与function() {}

这可以工作,也可以在循环中使用。

 var x = "OK"; setTimeout(alertOK.bind(null,x), 3000); x = "Would be WRONG"; console.log("before timeout:", x); function alertOK(x){ console.log("after timeout:",x); } 

因为你正在写一个字符串,它不像实际的闭包那样聪明。

 $('.mainNav2 > li').mouseleave(function(){ var someNum = Math.random(); $(this).attr('id', someNum); var t = setTimeout(function() { HideMenu(someNum); }, 200); $('li.clicked').mouseenter(function() { clearTimeout(t); }); }); function HideMenu(id) { $('#'+id).removeClass('clicked'); }