Chrome (peut-être Safari?) déclenche" flou " deux fois sur les champs de saisie lorsque le navigateur perd le focus

Voici un jsfiddle intéressant.

Dans Firefox:

  1. Exécutez le violon
  2. Cliquez dans la saisie de texte
  3. Cliquez ailleurs. Devrait dire "1 brouille".
  4. Cliquez à nouveau dans la saisie de texte.
  5. ALT-TAB vers une autre fenêtre. Fiddle devrait maintenant dire "2 flous".

Dans Chrome, à l'étape 5, il est dit "3 flous". Deux événements "flou" distincts sont déclenchés lorsque le navigateur entier perd le focus. Ceci est intéressant car cela signifie qu'il n'est pas sûr de supposons, dans un gestionnaire de "flou" , que l'élément avait réellement le focus juste avant l'envoi de l'événement; c'est - à - dire que la perte de focus-la transition de "être au focus" à "ne pas être au focus" - est la raison de l'événement. Lorsque deux événements "flou" sont générés, cette condition n'est pas satisfaite lors de la gestion du second événement, car l'élément n'est déjà pas mis au point.

Alors est-ce juste un bug? Est-il possible de dire qu'un "flou" de l'événement est faux?

21
demandé sur Pointy 2012-03-11 00:34:35

7 réponses

La raison pour laquelle il tire deux fois est à cause de window.onblur. Le flou de fenêtre déclenche un événement de flou sur tous les éléments de cette fenêtre dans le cadre du processus de capture/bouillonnement de javascript. Tout ce que vous devez faire est de tester la cible de l'événement pour être la fenêtre.

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/

18
répondu Fresheyeball 2012-03-10 21:47:10

Ceci est confirmé bogue Chrome. Voir le suivi des problèmes de chrome

La solution de contournement est dans la réponse acceptée.

3
répondu Chad Killingsworth 2013-01-28 18:56:45

Ignorer le 2ème flou:

var secondBlur = false;
this.onblur = function(){
    if(secondBlur)return;
    secondBlur = true;
    //do whatever
}
this.onfocus = function(){
    secondBlur = false;    
    //do whatever
}
2
répondu 2013-06-21 15:26:06

Ce n'est probablement pas ce que vous voulez entendre, mais la seule façon de le faire semble être de suivre manuellement si l'élément est porté ou non. Par exemple (violon ici):

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

Fait intéressant, je n'ai pas pu faire fonctionner cela dans jQuery (fiddle ici)... Je n'utilise vraiment pas beaucoup jQuery, peut-être que je fais quelque chose de mal ici?

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

Vous pouvez également essayer de comparer la cible de l'événement avec document.activeElement. Cet exemple ignorera les événements de flou ALT + tab et le flou événements résultant de cliquer sur Chrome... chrome. Cela pourrait être utile en fonction de la situation. Si l'utilisateur alt + tabs revient dans Chrome, c'est comme si la boîte n'avait jamais perdu le focus (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');
};​
​
1
répondu Dagg Nabbit 2012-03-10 21:49:06

Je suis sur la version Chrome 30.0.1599.101 m sur Windows 7 et ce problème semble avoir été corrigé.

1
répondu Ali Cheaito 2013-10-18 17:58:08

Je vis la même chose et les messages ci-dessus ont un sens quant à pourquoi. Dans mon cas, je voulais juste savoir si au moins un événement de flou s'était produit. En conséquence, j'ai trouvé que le simple retour de ma fonction de flou résolvait mon problème et empêchait l'événement suivant de se déclencher.

   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
répondu southpawlife 2014-12-06 07:24:56

On dirait qu'une bizarrerie d'angularjs donne une solution plus simple lors de l'utilisation de ng-blur; l'objet $ event n'est défini que si vous le transmettez:

ng-blur="onBlur($event)"

Donc (si vous n'utilisez pas ng-blur sur la fenêtre) vous pouvez vérifier:

$scope.onBlur = function( $event ) {
    if (event != undefined) {
       //this is the blur on the element
    }
}
1
répondu Patrick 2015-11-11 11:01:06