Chrome (возможно, Safari?) Дважды запускает «размытие» в полях ввода, когда браузер теряет фокус - PullRequest
21 голосов
/ 11 марта 2012

Вот интересный jsfiddle.

В Firefox:

  1. Запустить скрипку
  2. Нажмите на ввод текста
  3. Нажмите где-нибудь еще. Должен сказать "1 размывает".
  4. Снова нажмите на ввод текста.
  5. ALT-TAB в другое окно. Теперь скрипка должна сказать «2 пятна».

В Chrome на шаге 5 написано «3 пятна». Два отдельных события «размытия» запускаются, когда весь браузер теряет фокус. Это представляет интерес, поскольку означает, что в обработчике «размытия» небезопасно предполагать, что элемент действительно имел фокус непосредственно перед отправкой события; то есть, что потеря фокуса & mdash; переход от «быть в фокусе» к «не быть в фокусе» & mdash; является причиной события. Когда генерируются два события «размытия», это условие не выполняется во время обработки второго события, поскольку элемент уже не находится в фокусе.

Так это просто ошибка? Есть ли способ сказать, что событие «размытия» является поддельным?

Ответы [ 7 ]

18 голосов
/ 11 марта 2012

Причина, по которой он запускается дважды, из-за 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/

3 голосов
/ 28 января 2013

Это подтвержденная ошибка Chrome. См. Отслеживание проблем с хромом

Обходной путь находится в принятом ответе.

2 голосов
/ 21 июня 2013

Пропустить 2-е размытие:

var secondBlur = false;
this.onblur = function(){
    if(secondBlur)return;
    secondBlur = true;
    //do whatever
}
this.onfocus = function(){
    secondBlur = false;    
    //do whatever
}
1 голос
/ 11 ноября 2015

Похоже, странность angularjs дает более простое решение при использовании ng-blur; объект $ event определен только если вы передадите его:

ng-blur="onBlur($event)"

так (если вы не используете ng-blur в окне) вы можете проверить:

$scope.onBlur = function( $event ) {
    if (event != undefined) {
       //this is the blur on the element
    }
}
1 голос
/ 06 декабря 2014

Я испытываю то же самое, и приведенные выше сообщения имеют смысл, почему. В моем случае я просто хотел узнать, произошло ли хотя бы одно размытие. В результате я обнаружил, что только возвращение из функции размытия решило мою проблему и предотвратило запуск последующего события.

   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.
                }
            });
    }
1 голос
/ 18 октября 2013

Я нахожусь на Chrome версии 30.0.1599.101 m на Windows 7, и эта проблема, кажется, была исправлена.

1 голос
/ 11 марта 2012

Это, вероятно, не то, что вы хотите услышать, но единственный способ сделать это, похоже, вручную отследить, сфокусирован элемент или нет.Например ( скрипка здесь ):

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 ( скрипка здесь ) ... Я действительно не понимаюНе пользуетесь 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 + tab и события размытия, возникающие в результате нажатия на 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');
};​
​
...