web-dev-qa-db-fra.com

Quand un événement de "flou" se produit, comment puis-je savoir quel élément est concentré * ou *?

Supposons que j'attache une fonction blur à une zone de saisie HTML comme ceci:

<input id="myInput" onblur="function() { ... }"></input>

Existe-t-il un moyen d'obtenir l'ID de l'élément à l'origine du déclenchement de l'événement blur (l'élément sur lequel vous avez cliqué) à l'intérieur de la fonction? Comment?

Par exemple, supposons que j'ai une étendue comme celle-ci:

<span id="mySpan">Hello World</span>

Si je clique sur l'étendue juste après que l'élément d'entrée ait le focus, l'élément d'entrée perdra son focus. Comment la fonction sait-elle que vous avez cliqué sur mySpan?

PS: si l’événement onclick de la plage se produisait avant l’événement onblur de l’élément d’entrée, mon problème serait résolu car je pouvais définir une valeur de statut indiquant qu’un élément spécifique avait été cliqué.

PPS: Ce problème a pour origine le fait que je veux déclencher un contrôle AJAX autocompleter en externe (à partir d'un élément cliquable) pour afficher ses suggestions, sans que les suggestions ne disparaissent immédiatement à cause de l'événement blur sur l'élément en entrée. Je souhaite donc vérifier dans la fonction blur si un élément spécifique a été cliqué et, le cas échéant, ignorer l'événement de flou. 

153
Michiel Borkent

Hmm ... Dans Firefox, vous pouvez utiliser explicitOriginalTarget pour extraire l'élément sur lequel vous avez cliqué. Je m'attendais à ce que toElement fasse de même pour IE, mais cela ne semble pas fonctionner ... Cependant, vous pouvez extraire l'élément récemment ciblé du document:

function showBlur(ev)
{
   var target = ev.explicitOriginalTarget||document.activeElement;
   document.getElementById("focused").value = 
      target ? target.id||target.tagName||target : '';
}

...

<button id="btn1" onblur="showBlur(event)">Button 1</button>
<button id="btn2" onblur="showBlur(event)">Button 2</button>
<button id="btn3" onblur="showBlur(event)">Button 3</button>
<input id="focused" type="text" disabled="disabled" />

Caveat: Cette technique ne fonctionne pas pour les changements de focus causés par tabulation via des champs avec le clavier, et ne fonctionne pas du tout dans Chrome ou Safari. Le gros problème lié à l'utilisation de activeElement (sauf dans IE) est qu'il n'est pas mis à jour de manière cohérente avant le après l'événement blur a été traité et peut ne pas avoir de valeur valide pendant le traitement! Cela peut être atténué par une variation de la technique utilisée par Michiel :

function showBlur(ev)
{
  // Use timeout to delay examination of activeElement until after blur/focus 
  // events have been processed.
  setTimeout(function()
  {
    var target = document.activeElement;
    document.getElementById("focused").value = 
      target ? target.id||target.tagName||target : '';
  }, 1);
}

Cela devrait fonctionner dans la plupart des navigateurs modernes (testés dans Chrome, IE et Firefox), avec l'avertissement que Chrome ne met pas l'accent sur les boutons qui sont cliqué (vs onglets à). 

80
Shog9

2015 answer: selon UI Events , vous pouvez utiliser la propriété relatedTarget / de l'événement:

Utilisé pour identifier une variable EventTarget liée à un focus événement, en fonction du type d’événement.

Pour blur events,

relatedTarget : cible de l'événement cible de réception.

Exemple:

function blurListener(event) {
  event.target.className = 'blurred';
  if(event.relatedTarget)
    event.relatedTarget.className = 'focused';
}
[].forEach.call(document.querySelectorAll('input'), function(el) {
  el.addEventListener('blur', blurListener, false);
});
.blurred { background: orange }
.focused { background: Lime }
<p>Blurred elements will become orange.</p>
<p>Focused elements should become Lime.</p>
<input /><input /><input />

Note Firefox ne supportera pas relatedTarget avant la version 48 ( bogue 962251 , MDN ).

57
Oriol

Je l'ai finalement résolu avec un délai d'attente sur l'événement onblur (grâce aux conseils d'un ami autre que StackOverflow):

<input id="myInput" onblur="setTimeout(function() {alert(clickSrc);},200);"></input>
<span onclick="clickSrc='mySpan';" id="mySpan">Hello World</span>

Fonctionne à la fois dans FF et IE. 

18
Michiel Borkent

Il est possible d'utiliser l'événement mousedown du document au lieu du flou:

$(document).mousedown(function(){
  if ($(event.target).attr("id") == "mySpan") {
    // some process
  }
});
16
Evgeny Shmanev

Les instances de type FocusEvent ont l'attribut relatedTarget; toutefois, jusqu'à la version 47 du fichier FF, cet attribut renvoie null, sur 48, fonctionne déjà.

Vous pouvez voir plus ici .

5
rplaurindo

J'essaie également de faire en sorte que Autocompleter ignore le flou si un élément spécifique a cliqué et a une solution qui fonctionne, mais uniquement pour Firefox en raison de explicitOriginalTarget.

Autocompleter.Base.prototype.onBlur = Autocompleter.Base.prototype.onBlur.wrap( 
        function(origfunc, ev) {
            if ($(this.options.ignoreBlurEventElement)) {
                var newTargetElement = (ev.explicitOriginalTarget.nodeType == 3 ? ev.explicitOriginalTarget.parentNode : ev.explicitOriginalTarget);
                if (!newTargetElement.descendantOf($(this.options.ignoreBlurEventElement))) {
                    return origfunc(ev);
                }
            }
        }
    );

Ce code encapsule la méthode onBlur par défaut d'Autocompleter et vérifie si les paramètres ignoreBlurEventElement sont définis. s'il est défini, il vérifie chaque fois si l'élément cliqué est ignoreBlurEventElement ou non. Si c'est le cas, Autocompleter n'appelle pas OnBlur, sinon il appelle onBlur. Le seul problème avec cela est que cela ne fonctionne que dans Firefox car la propriété explicitOriginalTarget est spécifique à Mozilla. Maintenant, j'essaie de trouver un moyen différent d'utiliser explicitOriginalTarget. La solution que vous avez mentionnée vous oblige à ajouter manuellement le comportement onclick à l'élément. Si je ne parviens pas à résoudre le problème explicitOriginalTarget, je suppose que je suivrai votre solution.

2
matte

Pouvez-vous inverser ce que vous vérifiez et quand? Si vous vous rappelez ce qui était flou en dernier:

<input id="myInput" onblur="lastBlurred=this;"></input>

puis dans le onClick de votre extension, appelez function () avec les deux objets:

<span id="mySpan" onClick="function(lastBlurred, this);">Hello World</span>

Votre fonction pourrait alors décider de déclencher ou non le contrôle Ajax.AutoCompleter. La fonction contient l’objet cliqué et l’objet flou. OnBlur a déjà eu lieu, il ne fera donc pas disparaître les suggestions.

2
bmb

Comme indiqué dans cette réponse , vous pouvez vérifier la valeur de document.activeElement. document est une variable globale, vous n'avez donc pas besoin de faire de magie pour l'utiliser dans votre gestionnaire onBlur:

function myOnBlur(e) {
  if(document.activeElement ===
       document.getElementById('elementToCheckForFocus')) {
    // Focus went where we expected!
    // ...
  }
}
1
Kevin
  • document.activeElement peut être un nœud parent (par exemple, un nœud body car il se trouve dans une phase temporaire de basculement d'une cible à une autre), il n'est donc pas utilisable pour votre portée
  • ev.explicitOriginalTarget n'est pas toujours valorisé

Le meilleur moyen consiste donc à utiliser l'événement onclick on body pour comprendre indirectement que votre nœud (event.target) est flou. 

1
user6228847

Utilisez quelque chose comme ceci:

var myVar = null;

Et ensuite dans votre fonction:

myVar = fldID;

Et alors:

setTimeout(setFocus,1000)

Et alors:

function setFocus(){ document.getElementById(fldID).focus(); }

Code final:

<html>
<head>
    <script type="text/javascript">
        function somefunction(){
            var myVar = null;

            myVar = document.getElementById('myInput');

            if(myVar.value=='')
                setTimeout(setFocusOnJobTitle,1000);
            else
                myVar.value='Success';
        }
        function setFocusOnJobTitle(){
            document.getElementById('myInput').focus();
        }
    </script>
</head>
<body>
<label id="jobTitleId" for="myInput">Job Title</label>
<input id="myInput" onblur="somefunction();"></input>
</body>
</html>
1
Vikas

je pense que ce n'est pas possible, .____. avec IE, vous pouvez essayer d'utiliser window.event.toElement, mais cela ne fonctionne pas avec firefox!

1
stefano m

Vous pouvez corriger IE avec:

 event.currentTarget.firstChild.ownerDocument.activeElement

Cela ressemble à "explicitOriginalTarget" pour FF.

Antoine et J

0
Madbean

Je n'aime pas utiliser timeout pour coder javascript, donc je le ferais à l'inverse de Michiel Borkent. (N'a pas essayé le code derrière mais vous devriez avoir l'idée).

<input id="myInput" onblur="blured = this.id;"></input>
<span onfocus = "sortOfCallback(this.id)" id="mySpan">Hello World</span>

Dans la tête quelque chose comme ça

<head>
    <script type="text/javascript">
        function sortOfCallback(id){
            bluredElement = document.getElementById(blured);
            // Do whatever you want on the blured element with the id of the focus element


        }

    </script>
</head>
0
Ronan Quillevere

n'oubliez pas que la solution avec explicitOriginalTarget ne fonctionne pas pour les sauts texte-entrée-à-texte-entrée.

essayez de remplacer les boutons par les entrées de texte suivantes et vous verrez la différence:

<input id="btn1" onblur="showBlur(event)" value="text1">
<input id="btn2" onblur="showBlur(event)" value="text2">
<input id="btn3" onblur="showBlur(event)" value="text3">
0

Fonctionne dans Google Chrome v66.x, Mozilla v59.x et Microsoft Edge ... Solution avec jQuery.

Je teste dans Internet Explorer 9 et non pris en charge. 

$("#YourElement").blur(function(e){
     var InputTarget =  $(e.relatedTarget).attr("id"); // GET ID Element
     console.log(InputTarget);
     if(target == "YourId") { // If you want validate or make a action to specfic element
          ... // your code
     }
});

Commentez votre test dans d'autres versions d'Internet Explorer.

0
LuisEduardox

Je suggère d'utiliser des variables globales blurfrom et blurto. Ensuite, configurez tous les éléments qui vous intéressent pour attribuer leur position dans le DOM à la variable blurfrom lorsqu’ils perdent la mise au point. De plus, configurez-les de sorte que le focus soit défini sur la variable blurto sur leur position dans le DOM. Ensuite, vous pouvez utiliser une autre fonction pour analyser les données de flou et de blurto.

0
stalepretzel

Edit: Une façon simple de le faire serait de créer une variable qui garde la trace de chaque élément qui vous tient à coeur. Donc, si vous vous souciez de la perte de focus de 'myInput', définissez une variable sur focus.

<script type="text/javascript">
   var lastFocusedElement;
</script>
<input id="myInput" onFocus="lastFocusedElement=this;" />

Réponse originale: Vous pouvez passer 'this' à la fonction.

<input id="myInput" onblur="function(this){
   var theId = this.id; // will be 'myInput'
}" />
0
brock.holum

J'ai écrit une solution alternative comment rendre n'importe quel élément focalisable et "flou".

Cela consiste à créer un élément sous la forme contentEditable, à le masquer visuellement et à désactiver le mode d'édition lui-même:

el.addEventListener("keydown", function(e) {
  e.preventDefault();
  e.stopPropagation();
});

el.addEventListener("blur", cbBlur);
el.contentEditable = true;

DEMO

Remarque: Testé sous Chrome, Firefox et Safari (OS X). Pas sûr de IE.


Connexes: Je cherchais une solution pour VueJs, donc pour ceux qui sont intéressés/curieux de savoir comment mettre en œuvre une telle fonctionnalité avec la directive Vue Focusable, veuillez jetez un oeil .

0
Serhii Matrunchyk

J'ai joué avec cette même fonctionnalité et découvert que FF, IE, Chrome et Opera ont la capacité de fournir l'élément source d'un événement. Je n’ai pas testé Safari, mais j’imagine qu’il pourrait en être de même.

$('#Form').keyup(function (e) {
    var ctrl = null;
    if (e.originalEvent.explicitOriginalTarget) { // FF
        ctrl = e.originalEvent.explicitOriginalTarget;
    }
    else if (e.originalEvent.srcElement) { // IE, Chrome and Opera
        ctrl = e.originalEvent.srcElement;
    }
    //...
});
0
EricDuWeb