Wie kann ich herausfinden, welcher Elementfokus * auf * gegangen ist, wenn ein "Unschärfe" -Ereignis auftritt?

186

Angenommen, ich hänge eine blurFunktion wie folgt an ein HTML-Eingabefeld an:

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

Gibt es eine Möglichkeit, die ID des Elements, das das blurEreignis ausgelöst hat (das Element, auf das geklickt wurde), innerhalb der Funktion abzurufen? Wie?

Angenommen, ich habe eine Zeitspanne wie diese:

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

Wenn ich direkt nach dem Fokus des Eingabeelements auf die Spanne klicke, verliert das Eingabeelement seinen Fokus. Woher weiß die Funktion, dass darauf mySpangeklickt wurde?

PS: Wenn das Onclick-Ereignis des Bereichs vor dem Onblur-Ereignis des Eingabeelements auftreten würde, wäre mein Problem gelöst, da ich einen Statuswert festlegen könnte, der angibt, dass auf ein bestimmtes Element geklickt wurde.

PPS: Der Hintergrund dieses Problems ist, dass ich ein AJAX-Autocompleter-Steuerelement extern (von einem anklickbaren Element) auslösen möchte, um seine Vorschläge anzuzeigen, ohne dass die Vorschläge aufgrund des blurEreignisses im Eingabeelement sofort verschwinden . Daher möchte ich die blurFunktion überprüfen, ob auf ein bestimmtes Element geklickt wurde, und in diesem Fall das Unschärfeereignis ignorieren.

Michiel Borkent
quelle
Dies ist eine interessante Frage, die ich gerne hinter mir sehen würde - dh warum machst du das? Was ist der Kontext?
Rahul
Rahul und Roosteronacid, ich habe die Frage als Reaktion auf Ihre Kommentare (die PPS) aktualisiert.
Michiel Borkent
1
Da diese Informationen etwas alt sind, finden Sie hier eine neuere Antwort: stackoverflow.com/questions/7096120/…
Jonathan M

Antworten:

86

Hmm ... In Firefox können Sie explicitOriginalTargetdas Element ziehen, auf das geklickt wurde. Ich hatte erwartet toElement, dasselbe für den IE zu tun, aber es scheint nicht zu funktionieren ... Sie können jedoch das neu fokussierte Element aus dem Dokument ziehen:

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

Vorsichtsmaßnahme: Diese Technik funktioniert nicht bei Fokusänderungen, die durch das Durchblättern von Feldern mit der Tastatur verursacht werden, und funktioniert überhaupt nicht in Chrome oder Safari. Das große Problem bei der Verwendung activeElement(außer im IE) ist, dass es erst nach der blurVerarbeitung des Ereignisses konsistent aktualisiert wird und während der Verarbeitung möglicherweise überhaupt keinen gültigen Wert hat! Dies kann durch eine Variation der Technik gemildert werden, die Michiel letztendlich verwendet hat :

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

Dies sollte in den meisten modernen Browsern (getestet in Chrome, IE und Firefox) funktionieren, mit der Einschränkung, dass Chrome den Fokus nicht auf Schaltflächen legt, auf die geklickt wird (im Gegensatz zu Registerkarten).

Shog9
quelle
1
Ich habe lange nach etwas wie explizitem OriginalTarget gesucht. Wie haben Sie es entdeckt?
Kev
3
Untersuchte das Ereignisobjekt in FireBug. FWIW, die Eigenschaft ist Mozilla-spezifisch und auf MDC dokumentiert: developer.mozilla.org/en/DOM/event.explicitOriginalTarget
Shog9
2
Dies funktioniert in Firefox 3.6 und Safari 4.0.3 unter Windows nicht (oder funktioniert nicht mehr?).
Chetan S
1
@ Jonathan: Die Eigenschaft ist verfügbar, wird jedoch nicht aktualisiert, wenn das blurEreignis ausgelöst wird. Ich habe die Antwort mit Details aktualisiert. Haben Sie versucht, activeElement in Chrome oder Firefox dafür zu verwenden? Es gibt Ihnen das Element, das verwischt wird ...
Shog9
1
Funktioniert derzeit nicht mit FF 31: explizitOriginalTarget zeigt das aktuelle Unschärfeziel an. Document.activeElement ist beim Unschärfeereignis null.
Adrian Maire
75

Antwort 2015 : Laut UI-Ereignissen können Sie die relatedTargetEigenschaft des Ereignisses verwenden:

Wird verwendet, um eine sekundäre EventTargetBeziehung zu einem Fokusereignis zu identifizieren , abhängig von der Art des Ereignisses.

Für blurVeranstaltungen,

relatedTarget: Ereignisziel erhält Fokus.

Beispiel:

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

Hinweis Firefox wird erst relatedTargetab Version 48 unterstützt ( Fehler 962251 , MDN ).

Oriol
quelle
Firefox hat keine Unterstützung, aber es gibt ein Ticket: bugzilla.mozilla.org/show_bug.cgi?id=687787
Sandstrom
3
Jetzt hat es. Siehe hier .
Rplaurindo
liebe die Web-Community, jetzt ist alles viel einfacher ^ _ ^
am05mhz
6
Tolle Lösung. relatedTargetWird leider zurückgegeben, nullwenn der Zielempfangsfokus kein Eingabeelement ist.
Pedro Hoehl Carvalho
5
Wenn das Empfangen des Fokuselements kein Eingabeelement ist, fügen Sie ihm ein tabIndex="0"Attribut hinzu, und es funktioniert
Dany
19

Ich habe es schließlich mit einer Zeitüberschreitung beim Onblur-Ereignis gelöst (dank des Ratschlags eines Freundes, der nicht StackOverflow ist):

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

Funktioniert sowohl in FF als auch in IE.

Michiel Borkent
quelle
9
Wird dies übrigens in der Javascript-Welt als schlechte Praxis angesehen?
Michiel Borkent
1
alter post aber ich habe die gleiche frage. Unabhängig davon ist es das einzige, was den Job browserübergreifend zu erledigen scheint.
Joshs
Diese Antwort hat mir geholfen, ein anderes Problem zu lösen ... Danke Michael!
Alex
@MichielBorkent Dies ist eine schlechte Implementierung, da sie nicht ereignisgesteuert ist. Sie warten eine bestimmte Zeit und hoffen nur, dass es lange genug her ist. Je länger Sie warten, desto sicherer sind Sie, aber desto mehr Zeit verschwenden Sie, wenn Sie nicht so lange warten müssen. Vielleicht ist jemand auf einem wirklich alten / langsamen Gerät und diese Zeitüberschreitung reicht nicht aus. Leider bin ich hier, weil die Ereignisse mir nicht das bieten, was ich brauche, um festzustellen, ob in FireFox auf einen Iframe geklickt wird, aber es funktioniert für alle anderen Browser. Ich bin so versucht, diese Methode jetzt anzuwenden, obwohl es eine schlechte Praxis ist.
CTS_AE
1
Diese Frage ist ziemlich alt und geht auf das Jahr 2008 zurück. In der Zwischenzeit gab es möglicherweise bessere Ansätze. Können Sie die Antwort von 2015 ausprobieren?
Michiel Borkent
16

Es ist möglich, das Mousedown-Ereignis des Dokuments anstelle von Unschärfe zu verwenden:

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

Die FocusEventTypinstanzen haben ein relatedTargetAttribut, jedoch bis zur Version 47 des FF, insbesondere gibt dieses Attribut null zurück, von 48 funktioniert bereits.

Mehr können Sie hier sehen .

rplaurindo
quelle
2

Ich versuche auch, Autocompleter dazu zu bringen, Unschärfen zu ignorieren, wenn ein bestimmtes Element angeklickt hat und eine funktionierende Lösung hat, aber nur für Firefox aufgrund von explizitOriginalTarget

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

Dieser Code umschließt die Standardmethode onBlur von Autocompleter und prüft, ob die Parameter ignoreBlurEventElement festgelegt sind. Wenn es festgelegt ist, wird jedes Mal überprüft, ob das angeklickte Element ignoreBlurEventElement ist oder nicht. Wenn dies der Fall ist, ruft Autocompleter onBlur nicht an, andernfalls ruft es onBlur auf. Das einzige Problem dabei ist, dass es nur in Firefox funktioniert, da die Eigenschaft explizitOriginalTarget Mozilla-spezifisch ist. Jetzt versuche ich einen anderen Weg zu finden als mit explizitOriginalTarget. Bei der von Ihnen erwähnten Lösung müssen Sie dem Element das Verhalten beim Klicken manuell hinzufügen. Wenn es mir nicht gelingt, das explizite OriginalTarget-Problem zu lösen, werde ich Ihrer Lösung folgen.

matt
quelle
2

Können Sie rückgängig machen, was Sie wann überprüfen? Das heißt, wenn Sie sich daran erinnern, was zuletzt verschwommen war:

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

Rufen Sie dann im onClick für Ihre Spanne function () mit beiden Objekten auf:

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

Ihre Funktion könnte dann entscheiden, ob das Ajax.AutoCompleter-Steuerelement ausgelöst werden soll oder nicht. Die Funktion hat das angeklickte Objekt und das unscharfe Objekt. Das onBlur ist bereits aufgetreten, sodass die Vorschläge nicht verschwinden.

bmb
quelle
1

Verwenden Sie so etwas:

var myVar = null;

Und dann in Ihrer Funktion:

myVar = fldID;

Und dann:

setTimeout(setFocus,1000)

Und dann:

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

Endgültiger Code:

<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>
Vikas
quelle
1

Ich denke, es ist nicht möglich, mit IE können Sie versuchen, zu verwenden window.event.toElement, aber es funktioniert nicht mit Firefox!

stefano m
quelle
Funktioniert nicht mit Chrome oder Safari. Funktioniert möglicherweise nicht mit neuen IE-Versionen, die standardkompatibler sind.
Robocat
1

Wie in dieser Antwort angegeben , können Sie den Wert von überprüfen document.activeElement. documentist eine globale Variable, sodass Sie keine Magie ausführen müssen, um sie in Ihrem onBlur-Handler zu verwenden:

function myOnBlur(e) {
  if(document.activeElement ===
       document.getElementById('elementToCheckForFocus')) {
    // Focus went where we expected!
    // ...
  }
}
Kevin
quelle
1
  • document.activeElement kann ein übergeordneter Knoten sein (z. B. ein Körperknoten, da er sich in einer temporären Phase befindet, in der von einem Ziel zu einem anderen gewechselt wird), sodass er für Ihren Bereich nicht verwendet werden kann
  • ev.explicitOriginalTarget wird nicht immer bewertet

Der beste Weg ist also, onclick on body event zu verwenden, um indirekt zu verstehen, dass Ihr Knoten (event.target) unscharf ist


quelle
1

Funktioniert in Google Chrome v66.x, Mozilla v59.x und Microsoft Edge ... Lösung mit jQuery.

Ich teste in Internet Explorer 9 und werde nicht unterstützt.

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

Kommentieren Sie Ihren Test in anderen Internet Explorer-Versionen.

LuisEduardox
quelle
0

Bearbeiten: Eine hackige Möglichkeit wäre, eine Variable zu erstellen, die den Fokus für jedes Element verfolgt, das Sie interessiert. Wenn es Ihnen also wichtig ist, dass 'myInput' den Fokus verloren hat, setzen Sie eine Variable auf den Fokus.

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

Ursprüngliche Antwort: Sie können 'dies' an die Funktion übergeben.

<input id="myInput" onblur="function(this){
   var theId = this.id; // will be 'myInput'
}" />
brock.holum
quelle
Dies beantwortet die Frage nicht, hoffentlich habe ich es mit dem zusätzlichen Beispiel klarer gemacht
Michiel Borkent
0

Ich schlage vor, globale Variablen blurfrom und blurto zu verwenden. Konfigurieren Sie dann alle Elemente, die Sie interessieren, so, dass ihre Position im DOM der Variablen Unschärfe zugewiesen wird, wenn sie den Fokus verlieren. Konfigurieren Sie sie außerdem so, dass durch das Erzielen des Fokus die Variable blurto auf ihre Position im DOM gesetzt wird. Dann können Sie eine andere Funktion verwenden, um die Unschärfe- und Blurtodaten zu analysieren.

Stalepretzel
quelle
Es ist fast die Lösung, aber im Onblur-Ereignishandler musste ich bereits wissen, auf welches Element geklickt wurde, sodass eine Zeitüberschreitung bei Onblur dies für mich tat.
Michiel Borkent
0

Beachten Sie, dass die Lösung mit explizitOriginalTarget nicht für Sprünge von Texteingabe zu Texteingabe funktioniert.

Versuchen Sie, die Schaltflächen durch die folgenden Texteingaben zu ersetzen, und Sie werden den Unterschied sehen:

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

quelle
0

Ich habe mit derselben Funktion gespielt und festgestellt, dass FF, IE, Chrome und Opera das Quellelement eines Ereignisses bereitstellen können. Ich habe Safari noch nicht getestet, aber ich vermute, dass es etwas Ähnliches gibt.

$('#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;
    }
    //...
});
EricDuWeb
quelle
das funktioniert gut warum downvoting? entferne einfach originalEvent!
Fekiri Malek
0

Ich mag es nicht, Timeout beim Codieren von Javascript zu verwenden, also würde ich es anders machen als Michiel Borkent. (Habe den Code dahinter nicht ausprobiert, aber du solltest auf die Idee kommen).

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

Im Kopf so etwas

<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>
Ronan Quillevere
quelle
0

Sie können den IE reparieren mit:

 event.currentTarget.firstChild.ownerDocument.activeElement

Es sieht aus wie "explizitOriginalTarget" für FF.

Antoine und J.

Madbean
quelle
0

Ich habe eine alternative Lösung geschrieben wie man jedes Element fokussierbar und "unscharf" macht.

Es basiert darauf, ein Element als zu contentEditableerstellen und visuell auszublenden und den Bearbeitungsmodus selbst zu deaktivieren:

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

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

DEMO

Hinweis: Getestet in Chrome, Firefox und Safari (OS X). Ich bin mir nicht sicher über IE.


Verwandte Themen: Ich habe nach einer Lösung für VueJs gesucht. Wer also interessiert / neugierig ist, wie solche Funktionen mithilfe der Vue Focusable-Direktive implementiert werden können, sollte einen Blick darauf werfen .

Serhii Matrunchyk
quelle
-2

Diesen Weg:

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

Oder wenn Sie den Listener über JavaScript anhängen (in diesem Beispiel jQuery):

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

Edit : sorry. Ich habe die Frage falsch verstanden.

Armin Ronacher
quelle
3
Wenn Sie wissen, dass dies nicht die Antwort auf die Frage ist und Sie sie falsch verstanden haben, aktualisieren Sie sie bitte entsprechend oder löschen Sie sie.
TJ
-2


Ich denke, es ist leicht über jquery möglich, indem die Referenz des Feldes übergeben wird, das das Unschärfeereignis in "this" verursacht.
Zum Beispiel

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

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

Danke
Monika

Monika Sharma
quelle
-2

Sie könnten es so machen:

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

Ich sehe nur Hacks in den Antworten, aber es gibt tatsächlich eine sehr einfach zu verwendende integrierte Lösung: Grundsätzlich können Sie das Fokuselement folgendermaßen erfassen:

const focusedElement = document.activeElement

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

Thomas J.
quelle
Zumindest in meinem Fall funktioniert dies nicht, da das activeElement der Body ist. Wenn ich dies beim nächsten Rendern / Tick überprüfe, wird es richtig eingestellt. Aber es scheint, dass die Lösung von shog9 die einzig richtige Lösung ist, da sie sicherstellt, dass ein Tick getickt hat.
Mathijs Segers