【问题标题】:setTimeout() and setting parameterssetTimeout() 和设置参数
【发布时间】:2011-03-02 14:38:30
【问题描述】:

我有一些看起来像这样的 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);

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

【问题讨论】:

    标签: jquery settimeout


    【解决方案1】:

    虽然标记的正确答案是实现这一目标的一种方法……但我不认为它是正确的。

    见附件 JS Fiddle: http://jsfiddle.net/PWHw3/

    我们在这里所做的基本上是:

    setTimeout(function, timeout, param);
    

    例子:

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

    这对我有用,并且不需要通过两个函数。

    【讨论】:

    • 请注意,将参数传递给setTimeout()setInterval() 不是跨浏览器解决方案(即在Internet Explorer 中失败)。
    • @user113215 我不能代表早期的浏览器,但我可以验证它在 IE11 中是否有效。
    【解决方案2】:

    为了让它工作,并且在不使用 setTimeout 更改的讨厌的 eval 版本的情况下做到这一点:

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

    到这里:

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

    这样,您可以将someNum 的值传递到setTimeout 范围内的变量s

    【讨论】:

    • @Nyuszika7H:尝试实际阅读我的答案,您可能会发现我建议不要这样做,而我的解决方案没有这样做
    • 为什么是双重功能?你已经有了一个闭包。
    • @Thomas: 因为setTimeout 需要一个函数引用。外部函数是立即的,并返回一个供setTimeout 使用的函数引用。返回的函数引用在其范围内具有变量s,因此它在 setTimeout 触发时可用。
    • @Martin Jespersen - 我复制了你的代码,它从不调用 HideMenu 函数。
    • @Ben: 也许 HideMenu 函数不在作用域内?
    【解决方案3】:

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

    • 鼠标离开功能

      • 为变量someNum赋值。 someNum 的范围为 当前函数
      • 设置一个计时器,在 200 毫秒后评估字符串 "HideNum(someNum)"
      • 结束函数,离开函数范围
    • 200 毫秒通过

    • "HideNum(someNum)" 被评估。它应该抛出一个异常,因为变量 someNum 是未定义的。这就是不调用 HideNum 的原因 - 检查控制台中的错误。

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

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

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

    【讨论】:

      【解决方案4】:

      您要做的是创建一个匿名函数并在 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);
        });
      });
      

      【讨论】:

      • 我需要 ID 有一些更复杂的原因。我会试试匿名函数。但是为什么原版没有呢? w3schools.com 在他们将函数和参数放在引号中的示例中是否错误?
      • @Ben 避免使用 w3schools.com。在 w3fools.com(由 jQuery 团队制作)上找出原因。将字符串传递给 setTimeout 会打开您的代码到 XSS 和其他安全风险。
      • @Nyuszika7H 说了什么。 如果你会传递一个字符串,我认为你需要先评估参数,即 setTimeout("HideMenu(" + someNum + ")" ...但你真的不想这样做那个。
      【解决方案5】:

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

      1.使用匿名函数(推荐)

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

      2.setTimeoutsetInterval有一个隐藏功能:可以在超时后指定参数。

      setTimeout(hideMenu, 200, params);
      

      既然你已经在使用 jQuery,你不应该做一个单独的函数,而是扩展 jQuery 的原型,像这样:

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

      用法:

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

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

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


      更新

      已经有一个插件:jQuery.hoverIntent()。没必要自己做。它很容易使用,只需将mouseleave 事件替换为:

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

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

      【讨论】:

      • @ Nyuszika7H - 300 号码是什么?那是你对我的 someNum var 的代表吗?
      • @Ben Yep,但我在示例中将其更改为 'someNum'
      【解决方案6】:

      这很有效,也可以在循环中使用。

      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);
      }

      【讨论】:

        【解决方案7】:

        因为您正在编写一个字符串,它不如实际的闭包智能。

        $('.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');
        }
        

        【讨论】:

          猜你喜欢
          • 2019-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-18
          • 1970-01-01
          • 2020-01-03
          • 2023-02-22
          相关资源
          最近更新 更多