使用jQuery的focus()和blur()事件出现延迟问题

3
我正在尝试创建一个使用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);
            }
        );  
    });

您可以在这里查看。

你也有 StateChanger 函数的代码吗? - Russ Cam
@Rob- 你的演示在我的机器上非常流畅,我猜你是指导航菜单的悬停和高亮效果吧? - Russ Cam
实际上,Russ,在我的电脑上也非常流畅 - 直到我点击链接为止。然后,在“postheader”上更新图像之间存在延迟。虽然只有一小部分秒数,但是它是明显的。这在Chrome或Safari中根本不会发生,但在Firefox 3.5和IE 8中会发生。奇怪的是,它在使用速度较慢的javascript引擎的Firefox 2.0上运行良好。考虑到可能与Windows 7有关,我已经在XP和OS X上尝试过,并得到了相同的结果。 - Rob
2个回答

3

你的代码中存在很多不必要的作用域链的延长, 而较长的作用域链会导致解析时间变长。可以缩短为以下内容:

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

希望这样可以减少明显的延迟。如果在进行此更改后仍然看到明显的延迟,请发布事件处理程序函数的代码,因为该代码可能也有改进空间。
编辑:
针对您的评论,您可以使用传入的事件对象的target属性在函数中获取索引,该属性将是引发事件的元素。因此,要获取具有id为navbar的

而且,闭包很慢。选择Russ吧。+1 - Corey Ballou
好的,我正在尝试您的代码,但是使用$(e.target).prevAll().length来获取索引并不像人们期望的那样起作用。它总是返回0,因为在这种情况下,目标实际上是发出元素所引用的href。经过一番搜索,我确定可以使用$(e.target.id)获取ID,但我无法从仅知道ID的情况下找到确定索引的最佳方法。有什么想法吗? - Rob
啊,我的错,我意识到我们需要获取#navbar中所有<a>元素的索引。这很容易解决 - 由于包含每个<a><li>元素的索引将是相同的,而且e.target<a>元素,所以只需将$(e.target).prevAll().length修改为$(e.target.parentNode).prevAll().length,一切都会正常工作。我现在会更新答案并进行修改。 - Russ Cam
没错,这可以!然而它仍然没有解决延迟问题。我想火狐在处理某些事件时只是非常慢!不过我真的很感激你们对此帮助我的一切! - Rob
顺便提一下,在$(document).ready()中进行的$().load()操作返回的是完整的HTML文档,而不仅仅是你想要的<div> - Russ Cam
显示剩余5条评论

0

我是完全偶然解决了这个问题。我意识到我的问题并不是延迟,而是“事件冲突”的症状。

据我所知,问题在于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的帮助,我不认为我能解决这个问题,所以我再次感谢他在这方面给予的所有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接