【问题标题】:Lag problem with jQuery focus() and blur() eventsjQuery focus() 和 blur() 事件的滞后问题
【发布时间】:2010-12-11 01:10:21
【问题描述】:

我正在尝试创建一个使用一些 jQuery 的导航菜单。我希望键盘用户能够拥有与鼠标用户相同的体验,因此我将 hover() 事件处理程序中的功能复制到我的 focus()blur() 事件处理程序中。由于某种原因,当用户单击链接时,这会导致 Firefox 和 IE 出现明显的延迟,而在取出 focus()blur() 代码时不会出现这种情况。我该如何加快速度?在我有限的 javascript 知识允许的范围内,我已经做了尽可能多的优化,但我没有看到任何“加速”,所以我认为这可能与这些浏览器如何处理事件有关。

有什么我忽略的主要内容吗?或者有没有其他方法可以在不使用这些事件的同时保留键盘用户的可访问性?

        var statePad=0;

            function stateChanger(ourStatePad) {
                //the purpose of this function is to translate the current state of the menu into a different graphical representation of the menu state.
                var tempVar=ouStatePad;
                var tempArray = new Array;
                tempArray[5]=0;
                for (var x=0;x < 5;x++) {
                    tempArray[x]=tempVar % 10;
                    tempVar=(tempVar-tempArray[x])/10;
                }
                for (var arrayIndex=4;arrayIndex>=0;arrayIndex--) {
                   //Calculate the proper position in our CSS sprite, based on the each link's state, as well as it's neighbors'.
                    $(".block").eq(4 - arrayIndex)
                    .css(
                        "background-position",
                        //x-position
                        ((4 - arrayIndex) * -100) + "px " + 
                        //y-position
                        (tempArray[arrayIndex] + ((3 * tempArray[(arrayIndex) + 1]) * -30))) + "px";
                }
            }


        function hoverState(index,sign) {
            var placeholder=Math.pow(10,4-index);

            if (statePad != placeholder*2)
                statePad += (placeholder * sign);
            stateChanger(statePad);
}

        .click(function() {
            var index=$("#navbar a").index(this);
            statePad=Math.pow(10,(4-index))*2;
            stateChanger(statePad);
            $(".active").removeClass("active");
            $(this).addClass("active");
        })


        .hover(
            function () {
                hoverState($("#navbar a").index(this),1);
            },
            function () {
                hoverState($("#navbar a").index(this),-1);
            });

        $("#navbar a").focus( 
            function() {
                hoverState($("#navbar a").index(this),1);
            }
        );

        $("#navbar a").blur( 
            function() {
                hoverState($("#navbar a").index(this),-1);
            }
        );  
    });

您可以查看here

【问题讨论】:

  • 你也有stateChanger函数的代码吗?
  • @Rob- 你的演示在我的机器上非常流畅流畅,我认为你指的是导航菜单悬停和突出显示?
  • 实际上,Russ 在我的机器上也非常流畅——直到我点击一个链接。然后,点击和“postheader”上的图像更新之间存在延迟。这只是几分之一秒,但很明显。这在 Chrome 或 Safari 中根本不会发生,但在 Firefox 3.5 和 IE 8 上会发生。奇怪的是,它在使用慢得多的 javascript 引擎的 Firefox 2.0 上运行良好。认为这可能与 Windows 7 有关,我在 XP 和 OS X 上进行了尝试,并得到了相同的结果。

标签: jquery click mouseevent conflict jquery-events


【解决方案1】:

你的代码中有很多不必要的lengthening of the scope chain,更长的作用域链需要更长的时间来解决。可以简写如下

$("navbar a").click(blah) 
             .hover(foo,bar)
             .focus(foo)
             .blur(bar);

希望这会减少明显的延迟。如果您在进行此更改后仍然看到明显的延迟,请发布事件处理函数的代码,因为该代码也可能需要改进。

编辑:

作为对您的评论的回应,您可以使用传入的event 对象的target 属性获取函数中的索引,该属性将是引发事件的元素。因此,要获得&lt;ul&gt; 中ID navbar 中所有&lt;a&gt; 元素中&lt;a&gt; 元素的索引,我们可以使用每个&lt;a&gt; 都包含在@ 中的事实987654329@,因此每种情况下的索引都是相同的。考虑到这一点,event.target 将是引发点击事件的 &lt;a&gt; 元素,event.target.parentNode 将是 &lt;a&gt; 的父元素,即 &lt;li&gt;

要获取索引,您可以使用

function hoverState(e) { 
    // get the index of the <a> element, which will be the same
    // as the index of the <li> that contains it in the <ul>
    //
    var index = $(e.target.parentNode).prevAll().length; 
    //
    // get the sign
    var sign = (e.type === 'mouseenter' || e.type === 'focus')? 1 : -1;
} 

这将消除对包装 hoverState 的匿名函数事件处理程序的需要。

这里有一些修改后的代码

var statePad=0;

// the purpose of this function is to translate 
// the current state of the menu into a different 
// graphical representation of the menu state.
//
function stateChanger(ourStatePad) {

    var tempVar=ourStatePad;
    var tempArray = [0,0,0,0,0];
    for (var x=0;x < 5;x++) {
        tempArray[x]=tempVar % 10;
        tempVar=(tempVar-tempArray[x])/10;
    }
    // Calculate the proper position in our CSS sprite, 
    // based on the each link's state, as well as it's neighbors'
    //
    var arrayIndex=4;
    while (arrayIndex--) {

        $("#rightpostheader div.block").eq(4 - arrayIndex)
            .css(
                "backgroundPosition",
                //x-position
                ((4 - arrayIndex) * -100) + "px " + 
                //y-position
                (tempArray[arrayIndex] + ((3 * tempArray[(arrayIndex) + 1]) * -30))) + "px";
    }

}


function hoverState(e) {
    var index = $(e.target.parentNode).prevAll().length;
    var sign = (e.type === 'mouseenter' || 
                e.type === 'focus')? 1 : -1;
    var placeholder=Math.pow(10,4-index);

    if (statePad != placeholder*2)
        statePad += (placeholder * sign);
    stateChanger(statePad);
}

$("#navbar a")
    .click(function(e) {
        // might be able to rework this into using hoverState too
        var $this = $(e.target);

        // get the index of the parent <li>
        var index= $this.parent().prevAll().length;

        statePad=Math.pow(10,(4-index))*2;

        stateChanger(statePad);

        $("#navbar a").removeClass('active');
        $this.addClass('active');
    })
    .bind("mouseenter mouseleave focus blur", hoverState);  

【讨论】:

  • 最重要的是,关闭速度很慢。和拉斯一起去。 +1
  • 我想我肯定过分简化了我之前发布的代码,所以我发布了我正在使用的实际代码。如果不在匿名函数的上下文中这样做,我不知道如何获取当前元素的索引。这是否仍会被视为不必要的范围延长?
  • 哇...非常感谢您的深入回复。在阅读您对我的代码的修订时,我只有大约 4 个“啊哈”时刻。直到现在我才知道事件访问!
  • 好的,我正在尝试您的代码,但似乎使用 $(e.target).prevAll().length 来获取索引并不像人们期望的那样工作。它总是返回 0,因为在这种情况下,目标实际上是发布元素所引用的 href。经过一番谷歌搜索,我确定您可以使用 $(e.target.id) 获取 ID,但我无法仅通过知道 ID 找出确定索引的最佳方法。有什么想法吗?
  • 啊,我的错,我意识到我们需要在#navbar 中的所有&lt;a&gt; 元素中获取&lt;a&gt; 元素的索引。这很容易解决 - 因为包含每个 &lt;a&gt;e.target&lt;li&gt; 元素的索引将是相同的 &lt;a&gt; 元素,只需将 $(e.target).prevAll().length 修改为 $(e.target.parentNode).prevAll().length 就可以正常工作。我现在将使用此修正案更新答案
【解决方案2】:

我完全意外地解决了这个问题,有点。我意识到我的问题并不是真正的滞后,这只是“事件冲突”的症状。

据我所知,问题是focus() 是通过切换到链接或mousedown() 在可以接收焦点的元素上触发的。因此,每次点击链接时,它都会获得焦点。但是,直到释放鼠标,click() 事件才完成。所以我在 Firefox 和 IE 中看到的效果是 mousedown()mouseup() 之间的轻微延迟的结果。我尝试将代码中的.click() 事件处理换成mousedown(),因为这只是我要注意的一个事件,所以我决定将它集成到我的 hoverState() 函数中。我最终得到了这个:

function hoverState(e) {
    var index = $(e.target.parentNode).prevAll().length;
    if (e.type == 'mousedown') {
        statePad=Math.pow(10,(4-index))*2;
        $(".active").removeClass('active');
        $("#"+ e.target.id).addClass('active');
}
else {
   var sign = (e.type === 'mouseenter' || 
                 e.type === 'focus')? 1 : -1;
 var placeholder=Math.pow(10,4-index);
    if (statePad != placeholder*2)
        statePad += (placeholder * sign);
 $('h1').text(statePad + " " + e.type);
    }
    stateChanger(statePad);
}

$("#navbar a").bind("mouseenter mouseleave focus blur mousedown", hoverState);

但是,这会导致一些奇怪的行为搞砸了 statePad 变量。我回到了 Russ Cam 提供给我的代码,并开始重新思考。我在 Opera 中进行了尝试,但我还没有这样做,它运行良好。我在 Safari 和 Chrome 中尝试过,它们像往常一样运行良好。我在 Firefox 中尝试过,只是想了解它的不同之处,然后......它正在工作!

我回顾了我的代码,结果发现我仍在将 hoverState 函数绑定到 mousedown() 事件。我不完全确定为什么会这样,但确实如此。它也解决了 IE 中的问题。扼杀,它在 Chrome 中引起了一个新问题,它太小了,我什至不会担心。

如果没有 Russ 的帮助,我认为我无法解决这个问题,所以我想再次感谢他在这方面的所有帮助。

【讨论】:

    猜你喜欢
    • 2019-03-07
    • 2012-11-13
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多