Quando si verifica un evento di "sfocatura", come posso sapere quale elemento attivo è passato da * a *?


188

Supponiamo che allego una blurfunzione a una casella di input HTML come questa:

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

Esiste un modo per ottenere l'ID dell'elemento che ha causato l'attivazione blurdell'evento (l'elemento su cui è stato fatto clic) all'interno della funzione? Come?

Ad esempio, supponiamo che io abbia una durata come questa:

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

Se faccio clic sull'intervallo subito dopo l'attivazione dell'elemento di input, l'elemento di input perderà il focus. Come fa la funzione a sapere che è mySpanstato cliccato?

PS: Se l'evento onclick dell'intervallo si verificasse prima dell'evento onblur dell'elemento di input, il mio problema sarebbe risolto, perché potevo impostare un valore di stato che indicava che era stato fatto clic su un elemento specifico.

PPS: Lo sfondo di questo problema è che voglio innescare un controllo del completatore automatico AJAX esternamente (da un elemento cliccabile) per mostrare i suoi suggerimenti, senza che i suggerimenti scompaiano immediatamente a causa blurdell'evento sull'elemento di input. Quindi voglio controllare nella blurfunzione se è stato fatto clic su un elemento specifico e, in tal caso, ignorare l'evento sfocatura.


Questa è una domanda interessante che mi piacerebbe vedere dietro il ragionamento - cioè perché lo stai facendo? Qual è il contesto?
Rahul,

Rahul e roosteronacid, ho aggiornato la domanda come reazione ai tuoi commenti (il PPS).
Michiel Borkent,

1
Poiché queste informazioni sono un po 'vecchie, vedi qui per una risposta più recente: stackoverflow.com/questions/7096120/…
Jonathan M

Risposte:


86

Hmm ... In Firefox, puoi usare explicitOriginalTargetper estrarre l'elemento su cui hai fatto clic. Mi aspettavo toElementdi fare lo stesso per IE, ma non sembra funzionare ... Tuttavia, puoi estrarre l'elemento appena focalizzato dal documento:

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" />

Avvertenza: questa tecnica non funziona per i cambiamenti di messa a fuoco causati dalla tabulazione attraverso i campi con la tastiera e non funziona affatto in Chrome o Safari. Il grosso problema con l'utilizzo activeElement(tranne in IE) è che non viene costantemente aggiornato fino a quando l' blurevento non è stato elaborato e potrebbe non avere alcun valore valido durante l'elaborazione! Questo può essere mitigato con una variazione della tecnica che Michiel ha finito per usare :

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

Questo dovrebbe funzionare nella maggior parte dei browser moderni (testato in Chrome, IE e Firefox), con l'avvertenza che Chrome non si concentra sui pulsanti su cui si fa clic ( anziché su schede).


1
Ho cercato qualcosa di esplicito come TargetOriginalTarget da molto tempo. Come l'hai scoperto?
Kev

3
Esaminato l'oggetto evento in FireBug. FWIW, la proprietà è specifica di Mozilla e documentata su MDC: developer.mozilla.org/en/DOM/event.explicitOriginalTarget
Shog9

2
Questo non funziona (o ha smesso di funzionare?) In Firefox 3.6 e Safari 4.0.3 in Windows.
Chetan,

1
@Jonathan: la proprietà è disponibile, ma non viene aggiornata quando viene blurgenerato l' evento. Ho aggiornato la risposta con i dettagli. Hai provato a utilizzare activeElement per questo in Chrome o Firefox? Ti dà l'elemento sfocato ...
Shog9

1
In realtà non funziona su FF 31: esplicativeOriginalTarget mostra il target di sfocatura corrente, document.activeElement è nullo sull'evento di sfocatura.
Adrian Maire,

75

Risposta 2015 : secondo gli Eventi UI , puoi utilizzare la relatedTargetproprietà dell'evento:

Utilizzato per identificare un secondario EventTargetcorrelato a un evento Focus, a seconda del tipo di evento.

Per blureventi,

relatedTarget: destinazione dell'evento che riceve lo stato attivo.

Esempio:

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 />

Nota Firefox non supporterà relatedTargetfino alla versione 48 ( bug 962251 , MDN ).


Firefox non ha supporto, ma esiste un ticket: bugzilla.mozilla.org/show_bug.cgi?id=687787
sandstrom,

3
Adesso ha. Vedi qui .
rplaurindo,

amo la comunità web, ora è tutto molto più semplice ^ _ ^
am05mhz

6
Ottima soluzione Sfortunatamente, relatedTargetritornerà nullse l'obiettivo che riceve lo stato attivo non è un elemento di input.
Pedro Hoehl Carvalho,

5
Se la ricezione dell'elemento focus non è un elemento di input, aggiungi un tabIndex="0"attributo e funzionerà
Dany

19

Alla fine l'ho risolto con un timeout sull'evento onblur (grazie al consiglio di un amico che non è StackOverflow):

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

Funziona sia in FF che IE.


9
Questa è considerata una cattiva pratica nel mondo javascript a proposito?
Michiel Borkent,

1
vecchio post ma ho la stessa domanda. a prescindere, è l'unica cosa che sembra svolgere il lavoro su più browser.
joshs,

questa risposta mi ha aiutato con un TON risolvendo qualche altro problema ... Grazie Michael!
Alex,

@MichielBorkent questa è una cattiva implementazione perché non è guidata dagli eventi. Aspetti un determinato periodo di tempo e speri solo che sia stato abbastanza a lungo. Più a lungo aspetti più sicuro sei, ma anche più tempo perderai se non avessi bisogno di aspettare così a lungo. Forse qualcuno è su un dispositivo molto vecchio / lento e questo timeout non è sufficiente. Sfortunatamente sono qui perché gli eventi non mi forniscono ciò di cui ho bisogno per determinare se si fa clic su un iframe in FireFox, ma funziona per tutti gli altri browser. Sono così tentato di usare questo metodo ora anche se è una cattiva pratica.
CTS_AE

1
Questa domanda è piuttosto vecchia, risale al 2008. Nel frattempo potrebbero esserci stati approcci migliori. Puoi provare la risposta del 2015?
Michiel Borkent,

16

È possibile utilizzare l'evento mousedown del documento anziché la sfocatura:

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

8

Le FocusEventistanze del tipo hanno relatedTargetattributo, tuttavia, fino alla versione 47 dell'FF, in particolare, questo attributo restituisce null, poiché 48 funziona già.

Puoi vedere di più qui .


2

Sto anche cercando di fare in modo che Autocompleter ignori la sfocatura se un elemento specifico fa clic e ha una soluzione funzionante, ma solo per Firefox a causa di esplicitoTarget originale

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

Questo codice racchiude il metodo onBlur predefinito di Autocompleter e verifica se sono impostati i parametri ignoreBlurEventElement. se è impostato, controlla ogni volta per vedere se l'elemento cliccato è ignoreBlurEventElement o no. In tal caso, il completamento automatico non si chiama onBlur, altrimenti chiama onBlur. L'unico problema con questo è che funziona solo in Firefox perché la proprietà exploreOriginalTarget è specifica di Mozilla. Ora sto cercando di trovare un modo diverso rispetto all'utilizzo di espliciteOriginalTarget. La soluzione che hai citato richiede di aggiungere manualmente il comportamento onclick all'elemento. Se non riesco a risolvere il problema di Target originale, credo che seguirò la tua soluzione.


2

Puoi invertire ciò che stai controllando e quando? Cioè se ricordi ciò che è stato sfocato per ultimo:

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

e poi in onClick per il tuo intervallo, chiama la funzione () con entrambi gli oggetti:

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

La funzione potrebbe quindi decidere se attivare o meno il controllo Ajax.AutoCompleter. La funzione ha l'oggetto cliccato e l'oggetto sfocato. OnBlur è già successo, quindi non farà sparire i suggerimenti.


1

Usa qualcosa del genere:

var myVar = null;

E poi all'interno della tua funzione:

myVar = fldID;

E poi:

setTimeout(setFocus,1000)

E poi:

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

Codice finale:

<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

penso che non sia possibile, con IE puoi provare a usarlo window.event.toElement, ma non funziona con Firefox!


Non funziona con Chrome o Safari. Forse non funzionerà con le nuove versioni di IE che sono più compatibili con gli standard.
robocat,

1

Come indicato in questa risposta , è possibile verificare il valore di document.activeElement. documentè una variabile globale, quindi non devi fare nessuna magia per usarla nel tuo gestore onBlur:

function myOnBlur(e) {
  if(document.activeElement ===
       document.getElementById('elementToCheckForFocus')) {
    // Focus went where we expected!
    // ...
  }
}

1
  • document.activeElement potrebbe essere un nodo principale (ad esempio nodo del corpo perché è in una fase temporanea che passa da una destinazione a un'altra), quindi non è utilizzabile per il tuo ambito
  • ev.explicitOriginalTarget non è sempre valutato

Quindi il modo migliore è usare onclick on body event per capire indirettamente che il tuo nodo (event.target) è sfocato


1

Funziona con Google Chrome v66.x, Mozilla v59.x e Microsoft Edge ... Soluzione con jQuery.

Ho testato in Internet Explorer 9 e non supportato.

$("#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
     }
});

Commenta il tuo test in altre versioni di Internet Explorer.


0

Modifica: un modo bizzarro per farlo sarebbe quello di creare una variabile che tenga traccia del focus per ogni elemento a cui tieni. Quindi, se ti interessa che "myInput" abbia perso la messa a fuoco, imposta una variabile su di essa.

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

Risposta originale: è possibile passare 'questo' alla funzione.

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

questo non risponde alla domanda, spero di averlo chiarito con l'esempio aggiuntivo
Michiel Borkent,

0

Suggerisco di usare le variabili globali blurfrom e blurto. Quindi, configura tutti gli elementi che ti interessano per assegnare la loro posizione nel DOM alla sfocatura variabile quando perdono il focus. Inoltre, configurali in modo tale da ottenere lo stato attivo che imposta la variabile blurto sulla loro posizione nel DOM. Quindi, è possibile utilizzare un'altra funzione del tutto per analizzare la sfocatura e la sfocatura nei dati.


È quasi la soluzione, ma nel gestore di eventi onblur avevo già bisogno di sapere quale elemento era stato cliccato, quindi un timeout su onblur lo ha fatto per me.
Michiel Borkent,

0

tieni presente che la soluzione con esplicitoOriginalTarget non funziona per i salti da input di testo a input di testo.

prova a sostituire i pulsanti con i seguenti input di testo e vedrai la differenza:

<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

Ho giocato con questa stessa funzione e ho scoperto che FF, IE, Chrome e Opera hanno la capacità di fornire l'elemento sorgente di un evento. Non ho provato Safari, ma suppongo che potrebbe avere qualcosa di simile.

$('#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;
    }
    //...
});

funziona bene perché il downvoting? basta rimuovere originalEvent!
fekiri malek,

0

Non mi piace usare il timeout durante la codifica di JavaScript, quindi lo farei nel modo opposto di Michiel Borkent. (Non ho provato il codice dietro ma dovresti avere l'idea).

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

Nella testa qualcosa del genere

<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

È possibile correggere IE con:

 event.currentTarget.firstChild.ownerDocument.activeElement

Sembra "esplicitoTargetOriginal" per FF.

Antoine e J


0

Ho scritto una soluzione alternativa su come rendere qualsiasi elemento focalizzabile e "sfuocabile".

Si basa sul creare un elemento contentEditablee nasconderlo visivamente e disabilitare la modalità di modifica stessa:

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

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

DEMO

Nota: testato su Chrome, Firefox e Safari (OS X). Non sono sicuro di IE.


Correlati: ero alla ricerca di una soluzione per VueJs, quindi per coloro che erano interessati / curiosi su come implementare tale funzionalità utilizzando la direttiva Vue Focusable, dai un'occhiata .


-2

Per di qua:

<script type="text/javascript">
    function yourFunction(element) {
        alert(element);
    }
</script>
<input id="myinput" onblur="yourFunction(this)">

Oppure, se si collega il listener tramite JavaScript (jQuery in questo esempio):

var input = $('#myinput').blur(function() {
    alert(this);
});

Modifica : scusa. Ho letto male la domanda.


3
Se sei consapevole che questa non è la risposta alla domanda e la hai letta, ti preghiamo di aggiornarla di conseguenza o eliminarla.
TJ,

-2


Penso che sia facilmente possibile tramite jquery passando il riferimento del campo causando l'evento onblur in "questo".
Per es

<input type="text" id="text1" onblur="showMessageOnOnblur(this)">

function showMessageOnOnblur(field){
    alert($(field).attr("id"));
}

Grazie
Monika


-2

Potresti farlo in questo modo:

<script type="text/javascript">
function myFunction(thisElement) 
{
    document.getElementByName(thisElement)[0];
}
</script>
<input type="text" name="txtInput1" onBlur="myFunction(this.name)"/>

-2

Vedo solo degli hack nelle risposte, ma in realtà esiste una soluzione integrata molto facile da usare: in pratica puoi catturare l'elemento focus in questo modo:

const focusedElement = document.activeElement

https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement


Almeno nel mio caso, questo non funziona poiché activeElement è il corpo, se lo controllo al prossimo rendering / tick è impostato correttamente. Ma sembra che la soluzione di shog9 sia l'unica soluzione corretta in quanto assicura che un segno di spunta sia stato toccato.
Mathijs Segers,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.