Chrome(也许是Safari?)激发了“;模糊”;当浏览器失去焦点时,在输入字段上显示两次

Chrome (maybe Safari?) fires "blur" twice on input fields when browser loses focus

本文关键字:焦点 输入 两次 显示 失去 字段 Safari 也许 Chrome 模糊 浏览器      更新时间:2023-09-26

这里有一个有趣的jsfiddle

在Firefox中:

  1. 拉小提琴
  2. 点击文本输入
  3. 单击其他位置。应该说"1模糊"
  4. 再次点击输入的文本
  5. ALT-TAB到另一个窗口。Fiddle现在应该说"2个模糊"

在Chrome浏览器中,第5步显示"3个模糊"。当整个浏览器失去焦点时,会触发两个单独的"模糊"事件。这是令人感兴趣的,因为这意味着在"模糊"处理程序中,假设元素实际上在事件被调度之前就有焦点是不安全的;也就是说,注意力的丧失;从"专注"到"不专注"的转变;是事件的原因。当生成两个"模糊"事件时,在处理第二个事件期间,该条件不满足,因为元素已经不在焦点上。

这只是一个bug吗?有没有一种方法可以判断"模糊"事件是假的?

它之所以被触发两次是因为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/

这是确认的Chrome错误。查看Chromium Issue Tracker

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

跳过第二次模糊:

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

这可能不是您想要听到的,但唯一的方法似乎是手动跟踪元素是否聚焦。例如(此处为fiddle):

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)。。。我真的不怎么使用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;
});

您也可以尝试将事件的目标与CCD_2进行比较。此示例将忽略alt+选项卡模糊事件,以及单击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');
};​
​

我使用的是Windows 7上的Chrome版本30.0.1599.101 m,这个问题似乎已经解决。

我也有同样的经历,上面的帖子解释了原因。在我的情况下,我只想知道是否至少发生了一个模糊事件。因此,我发现从模糊函数返回就解决了我的问题,并阻止了后续事件的启动。

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

当使用ng模糊时,angularjs的一个奇怪之处似乎提供了一个更简单的解决方案;$event对象只有在传入时才定义:

ng-blur="onBlur($event)"

所以(如果你没有在窗口上使用ng模糊)你可以检查:

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