更改浏览器标签会不希望地触发焦点事件,特别是在 Google Chrome 中。

15

我刚刚注意到了一个关于焦点事件的小问题。显然,当切换到另一个浏览器标签页然后再切回来时,焦点会被激活。我不想让这种情况发生,有可能吗?

直到今天,我才注意到这一点。这里有一个小演示:http://jsfiddle.net/MJ6qb/1/

var times = 0;
$('input').on('focus', function() {
    times ++;
    $(this).after('<br>Focused '+times+' times');   
});

复现方法:先将焦点放在输入框中,然后切换浏览器选项卡,然后再切回来。所有浏览器似乎都会在切回选项卡时触发焦点事件,而且Google Chrome 19会触发两次

理想情况下,函数应该根本不会在切换浏览器选项卡时运行,只有在用户单击或按下 Tab 时才运行,但现在我意识到Chrome的问题后,我对此有些更担心了,因为它会导致我真实应用程序中不必要的连续 AJAX 请求(这是为了获取自动完成结果,需要保持最新状态,但不需要使用 keyup 事件那么频繁)。

看起来这与 jQuery 无关(我尝试过原生 JavaScript),但我可以使用 jQuery 来解决。我能做些什么吗?我知道可以使用 jQuery 的 one() 方法,但我确实希望函数可以运行多次。


1
略微不相关,但您可能能够检测浏览器选项卡何时聚焦或失焦,并覆盖默认行为,就像这个一样。从我所看到的情况来看,Chrome双重触发是一个已知的错误 - jeffjenx
啊,谢谢你提醒,我没意识到这是一个已知的 bug,在发布之前只是在 Chrome 中测试代码以确保它不是 Firefox 的问题(因为我是在 Firefox 中开发)。我有点想放弃并“让它自己运行”,但这真的很烦人。我会看看那个答案中的代码能否解决问题。 - Wesley Murch
1
您所遇到的行为是预期的。当您离开该选项卡时,您取消了该文本框的焦点,当您返回时,又重新聚焦它。离开到另一个应用程序也是同样的情况。不幸的是,我无法想到一种覆盖或绕过此行为的方法。 - jeffjenx
只要模糊事件也触发了(似乎是这样),我想这就有道理了 - 我以前从未意识到。 - Wesley Murch
2个回答

9
尝试使用这个
var times = 0;
var prevActiveElement;

    $( window ).on( "blur", function(e){
            prevActiveElement = document.activeElement;
    });

    $('input').on('focus', function() {
        if (document.activeElement === prevActiveElement) {
            return;
        }
        prevActiveElement = document.activeElement;
        times++;
        $(this).after('<br>Focused ' + times + ' times');
    }).on( "blur", function(){
        prevActiveElement = null;  
    });​

看起来这个可行!感谢你的解决方法!而且我从未听说过 activeElement,所以再次感谢你提供这个信息。 - Wesley Murch
顺便说一句,这在生产环境中也可以完美地处理多个输入:http://jsfiddle.net/MJ6qb/5/(如果你感兴趣,请打开控制台以查看请求)。 - Wesley Murch
@WesleyMurch,$("body").on("blur")根本没有被触发。Blur不会冒泡,你可能想要使用$("body").on( "focusout", "[data-autocomplete]", fn)。而对于focus的等效操作是$("body").on( "focusin", "[data-autocomplete]", fn) - Esailija
啊,谢谢你发现了这个问题,我把模糊事件附加到了错误的对象上。 - Wesley Murch
还在适应使用 on 而不是 live。好的,通过链接 .on('focusout', function(){ prevActiveElement = null; }); 解决了。太棒了,谢谢。 - Wesley Murch

3
尝试以下方法解决这个问题:
var times = 0, foc=true;

$(window).on('focus', function() {
    foc = false;
    setTimeout(function() {foc=true}, 200);
});

$('input').on('focus', function() {
    if (foc || times===0) {
        times ++;
        $(this).after('<br>Focused '+times+' times');   
    }
});

FIDDLE


到目前为止,除非您首先使用另一种方法(例如TAB或首先单击另一个输入),否则不会在单击时触发 - 仍在测试中。但是,是的,这是一个有趣的解决方案! - Wesley Murch
很奇怪,在Chrome上一切正常,焦点事件每次都会触发,但在浏览器标签页更改时却不会。 - adeneo
如果您在执行其他操作之前点击输入框,它似乎就无法正常工作。@adeno,您试过了吗? - Wesley Murch
是的,在Firefox中也是这样。我必须先“聚焦”到窗口,然后再聚焦到输入字段才能触发事件。 - jeffjenx
啊,我明白了,之前没试过那个方法,总是先点击窗口,但还是更新了答案,现在应该可以了! - adeneo
是的,看起来现在可以工作了。如果没有其他答案,我绝对会使用这个。setTimeout是一个不错的技巧,但似乎有1%的hacky。非常感谢! - Wesley Murch

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