当浏览器失去焦点时,Chrome(可能是Safari?)会在输入字段上激活两次“模糊”

时间:2012-03-10 20:34:36

标签: javascript google-chrome javascript-events safari

Here is an interesting jsfiddle.

在Firefox中:

  1. 跑小提琴
  2. 点击文字输入
  3. 点击其他地方。应该说“1模糊”。
  4. 再次点击文字输入。
  5. ALT-TAB到另一个窗口。小提琴现在应该说“2次模糊”。
  6. 在Chrome中,在第5步,它显示“3次模糊”。当整个浏览器失去焦点时,会触发两个单独的“模糊”事件。这是有意义的,因为它意味着在“模糊”处理程序中假设元素实际上在调度事件之前具有焦点是不安全的;也就是说,失去焦点 - 从“聚焦”到“不在焦点”的过渡 - 是事件发生的原因。当生成两个“模糊”事件时,在处理第二个事件期间不满足该条件,因为该元素已经不在焦点上。

    这只是一个错误吗?有没有办法告诉“模糊”事件是假的?

7 个答案:

答案 0 :(得分:18)

两次射击的原因是因为window.onblur。窗口模糊会触发该窗口中所有元素的模糊事件,这是javascript捕获/冒泡过程的一部分。您需要做的就是测试事件目标作为窗口。

var blurCount = 0;
var isTargetWindow = false;
$(window).blur(function(e){
    console.log(e.target);
    isTargetWindow = true;
});
$(window).focus(function(){
    isTargetWindow = false;
});
$('input').blur(function(e) {
    if(!isTargetWindow){         
       $('div').text(++blurCount + ' blurs');
    }
    console.log(e.target);
});

http://jsfiddle.net/pDYsM/4/

答案 1 :(得分:3)

这是Chrome确认的错误。 See the Chromium Issue Tracker

解决方法在接受的答案中。

答案 2 :(得分:2)

跳过第二次模糊:

var secondBlur = false;
this.onblur = function(){
    if(secondBlur)return;
    secondBlur = true;
    //do whatever
}
this.onfocus = function(){
    secondBlur = false;    
    //do whatever
}

答案 3 :(得分:1)

这可能不是你想听到的,但唯一的方法就是手动跟踪元素是否聚焦。例如(fiddle here):

var blurCount = 0;
document.getElementsByTagName('input')[0].onblur = function(e) {
    if (!e) e = window.event;
    console.log('blur', e);
    if (!(e.target || e.srcElement)['data-focused']) return;
    (e.target || e.srcElement)['data-focused'] = false;
    document.getElementsByTagName('div')[0].innerHTML = (++blurCount + ' blurs');
};
document.getElementsByTagName('input')[0].onfocus = function(e) {
    if (!e) e = window.event;
    console.log('focus', e);
    (e.target || e.srcElement)['data-focused'] = true;
};

有趣的是,我无法在jQuery中使用它(fiddle here)...我真的不使用jQuery,也许我在这里做错了什么?

var blurCount = 0;
$('input').blur(function(e) {
    console.log('blur', e);
    if (!(e.target || e.srcElement)['data-focused']) return;
    (e.target || e.srcElement)['data-focused'] = false;
    $('div').innerHTML = (++blurCount + ' blurs');
});
$('input').focus(function(e) {
    console.log('focus', e);
    (e.target || e.srcElement)['data-focused'] = true;
});

您还可以尝试将事件的目标与document.activeElement进行比较。此示例将忽略alt +标签模糊事件以及点击Chrome的... chrome时产生的模糊事件。根据具体情况,这可能很有用。如果用户将alt +标签返回Chrome,就好像该框永远不会失去焦点(fiddle)。

var blurCount = 0;
document.getElementsByTagName('input')[0].onblur = function(e) {
    if (!e) e = window.event;
    console.log('blur', e, document.activeElement, (e.target || e.srcElement));
    if ((e.target || e.srcElement) == document.activeElement) return;
    document.getElementsByTagName('div')[0].innerHTML = (++blurCount + ' blurs');
};​
​

答案 4 :(得分:1)

我在Windows 7上使用的是Chrome版本30.0.1599.101 m,此问题似乎已修复。

答案 5 :(得分:1)

我遇到了同样的情况,以上帖子对于为什么有意义。在我的情况下,我只是想知道至少是否发生过一次模糊事件。结果我发现只是从我的模糊函数返回解决了我的问题并阻止后续事件被触发。

   function handleEditGroup(id) {
        var groupLabelObject = $('#' + id);
        var originalText = groupLabelObject.text();

        groupLabelObject.attr('contenteditable', true)
            .focus().blur(function () {
                $(this).removeAttr('contenteditable');
                $(this).text($(this).text().substr(0, 60));

                if ($(this).text() != originalText) {
                    alert("Change Found");
                    return; //<--- Added this Return.
                }
            });
    }

答案 6 :(得分:1)

使用ng-blur时,看起来像angularjs的奇怪之处提供了一个更简单的解决方案; $ event对象仅在您传递时才定义:

ng-blur="onBlur($event)"

所以(如果您没有在窗口上使用ng-blur),您可以检查:

$scope.onBlur = function( $event ) {
    if (event != undefined) {
       //this is the blur on the element
    }
}