Kiedy pojawia się zdarzenie „rozmycia”, jak mogę dowiedzieć się, który element skupił się na *?

187

Załóżmy, że dołączam blurfunkcję do pola wprowadzania HTML, takiego jak to:

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

Czy istnieje sposób na uzyskanie identyfikatora elementu, który spowodował blur zdarzenia (elementu, który został kliknięty) wewnątrz funkcji? W jaki sposób?

Załóżmy na przykład, że mam taki zakres:

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

Jeśli kliknę rozpiętość zaraz po skupieniu elementu wejściowego, element wejściowy straci swoje skupienie. Skąd funkcja wie, że tak byłomySpan że została kliknięta?

PS: Gdyby zdarzenie onclick zakresu miało miejsce przed zdarzeniem onblur elementu wejściowego, mój problem zostałby rozwiązany, ponieważ mogłem ustawić pewną wartość statusu wskazującą, że kliknięto określony element.

PPS: Tło tego problemu polega na tym, że chcę uruchomić zewnętrzną kontrolę autouzupełniacza AJAX (z klikalnego elementu), aby pokazać jej sugestie, bez sugestii znikających natychmiast z powodu blurzdarzenia na elemencie wejściowym. Chcę więc sprawdzić w blurfunkcji, czy kliknięto jeden konkretny element, a jeśli tak, zignoruj ​​zdarzenie rozmycia.

Michiel Borkent
źródło
To interesujące pytanie, które chciałbym zobaczyć za uzasadnieniem - tj. Dlaczego to robisz? Jaki jest kontekst?
Rahul
Rahul i roosteronacid, zaktualizowałem pytanie w odpowiedzi na twoje komentarze (PPS).
Michiel Borkent,
1
Ponieważ te informacje są nieco stare, zobacz tutaj nowszą odpowiedź: stackoverflow.com/questions/7096120/...
Jonathan M

Odpowiedzi:

86

Hmm ... W Firefoksie możesz użyć explicitOriginalTargetelementu, który został kliknięty. Oczekiwałem, toElementże zrobię to samo dla IE, ale wydaje się, że to nie działa ... Możesz jednak pobrać nowo skoncentrowany element z dokumentu:

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

Ostrzeżenie: ta technika nie działa w przypadku zmian fokusów spowodowanych tabulowaniem pól za pomocą klawiatury i nie działa w ogóle w Chrome ani Safari. Duży problem z użyciem activeElement(z wyjątkiem IE) jest to, że nie jest stale aktualizowana, aż poblur zdarzenie zostało przetworzone, a może nie mieć prawidłową wartość w ogóle podczas przetwarzania! Można to złagodzić poprzez zmianę techniki, w której Michiel skończył stosując :

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

Powinno to działać w większości nowoczesnych przeglądarek (testowanych w Chrome, IE i Firefox), z zastrzeżeniem, że Chrome nie ustawia ostrości na klikane przyciski (w porównaniu z kartami).

Shog9
źródło
1
Od dłuższego czasu szukałem czegoś takiego jak wyraźnyOriginalTarget. Jak to odkryłeś?
Kev
3
Zbadał obiekt zdarzenia w FireBug. FWIW, właściwość jest specyficzna dla Mozilli i udokumentowana na MDC: developer.mozilla.org/en/DOM/event.explicitOriginalTarget
Shog9
2
To nie działa (lub przestało działać?) W Firefox 3.6 i Safari 4.0.3 w Windows.
Chetan S
1
@Jathanathan: właściwość jest dostępna, ale nie jest aktualizowana po uruchomieniu blurzdarzenia. Zaktualizowałem odpowiedź ze szczegółami. Czy próbowałeś użyć activeElement do tego w Chrome lub Firefox? Daje zamazany element ...
Shog9,
1
Właściwie nie działa na FF 31: wyraźneOriginalTarget pokazuje bieżący cel rozmycia, document.activeElement jest zerowy w przypadku zdarzenia rozmycia.
Adrian Maire,
75

Odpowiedź 2015 : zgodnie z Zdarzeniami interfejsu użytkownika można użyć relatedTargetwłaściwości zdarzenia:

Służy do identyfikowania drugorzędnego EventTargetpowiązanego ze zdarzeniem Focus, w zależności od rodzaju zdarzenia.

Na blurimprezy

relatedTarget: fokus docelowy zdarzenia .

Przykład:

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

Uwaga Firefox nie będzie obsługiwany relatedTargetdo wersji 48 ( błąd 962251 , MDN ).

Oriol
źródło
Firefox nie ma wsparcia, ale jest bilet: bugzilla.mozilla.org/show_bug.cgi?id=687787
sandstrom
3
Teraz ma. Zobacz tutaj .
rplaurindo,
uwielbiam społeczność internetową, teraz wszystko jest o wiele łatwiejsze ^ _ ^
am05mhz
6
Świetne rozwiązanie. Niestety, relatedTargetpowróci, nulljeśli docelowy fokus nie jest elementem wejściowym.
Pedro Hoehl Carvalho,
5
Jeśli odbieranie elementu fokusowego nie jest elementem wejściowym, dodaj tabIndex="0"do niego atrybut, a zadziała
Dany
19

Rozwiązałem go w końcu z limitem czasu na zdarzeniu onblur (dzięki radom znajomego, który nie jest StackOverflow):

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

Działa zarówno w FF, jak i IE.

Michiel Borkent
źródło
9
Czy jest to uważane za złą praktykę w świecie javascript btw?
Michiel Borkent
1
stary post, ale mam to samo pytanie. niezależnie od tego, wydaje się, że jest to jedyna rzecz, która pozwala wykonać zadanie w różnych przeglądarkach.
joshs
ta odpowiedź pomogła mi TON, rozwiązując jakiś inny problem ... Dzięki Michael!
Alex
@MichielBorkent jest to zła implementacja, ponieważ nie jest sterowana zdarzeniami. Czekasz określoną ilość czasu i masz tylko nadzieję, że minęło wystarczająco dużo czasu. Im dłużej zwlekasz, tym jesteś bezpieczniejszy, ale tym więcej czasu będziesz tracić, jeśli nie będziesz musiał czekać tak długo. Może ktoś ma naprawdę stare / wolne urządzenie i ten limit czasu nie wystarczy. Niestety jestem tutaj, ponieważ wydarzenia nie dostarczają mi tego, co muszę ustalić, czy w FireFox jest klikany element iframe, ale działa on dla wszystkich innych przeglądarek. Kusi mnie teraz, aby użyć tej metody, mimo że jest to zła praktyka.
CTS_AE
1
To pytanie jest dość stare, sięga roku 2008. Tymczasem być może były lepsze podejścia. Czy możesz wypróbować odpowiedź z 2015 roku?
Michiel Borkent,
16

Możliwe jest użycie zdarzenia mousedown dokumentu zamiast rozmycia:

$(document).mousedown(function(){
  if ($(event.target).attr("id") == "mySpan") {
    // some process
  }
});
Evgeny Shmanev
źródło
8

FocusEventInstancje typu mają relatedTargetatrybut, jednak do wersji 47 FF, w szczególności ten atrybut zwraca null, z 48 już działa.

Możesz zobaczyć więcej tutaj .

rplaurindo
źródło
2

Staram się również, aby Autouzupełnianie ignorował rozmycie, jeśli kliknąłby określony element i miał działające rozwiązanie, ale tylko dla Firefoksa z powodu jawnegoOriginalTarget

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

Ten kod otacza domyślną metodę onBlur autouzupełniacza i sprawdza, czy ustawione są parametry ignoreBlurEventElement. jeśli jest ustawiony, sprawdza za każdym razem, czy kliknięty element jest ignoreBlurEventElement, czy nie. Jeśli tak jest, autouzupełnianie nie caluje na Blur, w przeciwnym razie wywołuje Blur. Jedynym problemem jest to, że działa tylko w przeglądarce Firefox, ponieważ właściwość wyraźneOriginalTarget jest specyficzna dla Mozilli. Teraz próbuję znaleźć inny sposób niż użycie jawnegoOriginalTarget. Rozwiązanie, o którym wspomniałeś, wymaga ręcznego dodania zachowania elementu do elementu. Jeśli nie uda mi się rozwiązać problemu z jawnymOriginalTarget, chyba postąpię zgodnie z twoim rozwiązaniem.

matowy
źródło
2

Czy możesz cofnąć to, co sprawdzasz i kiedy? To znaczy, jeśli pamiętasz, co zostało zamazane ostatnio:

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

a następnie w onClick dla swojego zakresu, wywołaj funkcję () dla obu obiektów:

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

Twoja funkcja może wtedy zdecydować, czy uruchomić kontrolę Ajax.AutoCompleter. Funkcja ma kliknięty obiekt i obiekt zamazany. OnBlur już się wydarzył, więc nie sprawi, że sugestie znikną.

bmb
źródło
1

Użyj czegoś takiego:

var myVar = null;

A potem w twojej funkcji:

myVar = fldID;

I wtedy:

setTimeout(setFocus,1000)

I wtedy:

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

Ostateczny kod:

<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
źródło
1

myślę, że nie jest to możliwe, z IE możesz spróbować użyć window.event.toElement, ale nie działa z Firefoksem!

Stefan M
źródło
Nie działa z Chrome ani Safari. Może nie będzie działać z nowymi wersjami IE, które są bardziej kompatybilne ze standardami.
robocat
1

Jak zauważono w tej odpowiedzi , możesz sprawdzić wartość document.activeElement. documentjest zmienną globalną, więc nie musisz robić żadnej magii, aby użyć jej w module obsługi onBlur:

function myOnBlur(e) {
  if(document.activeElement ===
       document.getElementById('elementToCheckForFocus')) {
    // Focus went where we expected!
    // ...
  }
}
Kevin
źródło
1
  • document.activeElement może być węzłem nadrzędnym (na przykład węzłem ciała, ponieważ jest w fazie tymczasowej przełączania się z celu na inny), więc nie można go użyć w twoim zakresie
  • ev.explicitOriginalTarget nie zawsze jest wyceniany

Najlepszym sposobem jest użycie zdarzenia kliknięcia na ciele do pośredniego zrozumienia twojego węzła (event.target) jest rozmazany


źródło
1

Działa w Google Chrome v66.x, Mozilla v59.x i Microsoft Edge ... Rozwiązanie z jQuery.

Testuję w Internet Explorerze 9 i nie jest obsługiwany.

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

Skomentuj swój test w innych wersjach Internet Explorera.

LuisEduardox
źródło
0

Edycja: hacking sposób to zrobić, aby utworzyć zmienną, która śledzi fokus dla każdego elementu, na którym ci zależy. Tak więc, jeśli zależy ci na tym, aby „myInput” stracił fokus, ustaw dla niego zmienną fokus.

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

Oryginalna odpowiedź: Możesz przekazać „to” do funkcji.

<input id="myInput" onblur="function(this){
   var theId = this.id; // will be 'myInput'
}" />
brock.holum
źródło
to nie odpowiada na pytanie, mam nadzieję, że wyjaśniłem to dodatkowym przykładem
Michiel Borkent
0

Sugeruję użycie zmiennych globalnych blurfrom i blurto. Następnie skonfiguruj wszystkie elementy, które chcesz, aby przypisały swoją pozycję w DOM do zmiennej blurrom, gdy stracą fokus. Dodatkowo skonfiguruj je tak, aby uzyskanie fokusu ustawiło zmienną blurto na ich pozycję w DOM. Następnie możesz użyć innej funkcji do analizy rozmycia i danych rozmycia do danych.

czerstwypretzel
źródło
To prawie rozwiązanie, ale w module obsługi zdarzeń onblur musiałem już wiedzieć, który przedmiot został kliknięty, więc przerwa na nim zrobiła to za mnie.
Michiel Borkent
0

należy pamiętać, że rozwiązanie z jawnymOriginalTarget nie działa w przypadku skoków wprowadzania tekstu na tekst.

spróbuj zastąpić przyciski następującymi danymi wejściowymi, a zobaczysz różnicę:

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

źródło
0

Grałem z tą samą funkcją i odkryłem, że FF, IE, Chrome i Opera mają możliwość zapewnienia elementu źródłowego wydarzenia. Nie testowałem Safari, ale przypuszczam, że może mieć coś podobnego.

$('#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
źródło
to działa dobrze, dlaczego głosowanie? po prostu usuń originalEvent!
fekiri malek
0

Nie lubię używać limitu czasu podczas kodowania javascript, więc zrobiłbym to w odwrotny sposób niż Michiel Borkent. (Nie wypróbowałem kodu, ale powinieneś o tym pomyśleć).

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

W głowie coś takiego

<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
źródło
0

Możesz naprawić IE za pomocą:

 event.currentTarget.firstChild.ownerDocument.activeElement

Wygląda to jak „wyraźneOriginalTarget” dla FF.

Antoine And J.

Madbean
źródło
0

Napisałem alternatywne rozwiązanie jak uczynić dowolny element możliwym do zogniskowania i „rozmytym”.

Polega na utworzeniu elementu jako contentEditablewizualnym ukryciu go i wyłączeniu samego trybu edycji:

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

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

PRÓBNY

Uwaga: Testowane w Chrome, Firefox i Safari (OS X). Nie jestem pewien co do IE.


Powiązane: Szukałem rozwiązania dla VueJ, więc dla tych, którzy są zainteresowani / ciekawi, jak wdrożyć taką funkcjonalność za pomocą dyrektywy Vue Focusable, spójrz .

Serhii Matrunchyk
źródło
-2

Tą drogą:

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

Lub jeśli dołączasz nasłuchiwanie przez JavaScript (jQuery w tym przykładzie):

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

Edycja : przepraszam. Źle odczytałem pytanie.

Armin Ronacher
źródło
3
Jeśli masz świadomość, że nie jest to odpowiedź na pytanie i źle je przeczytałeś, zaktualizuj je odpowiednio lub usuń.
TJ
-2


Myślę, że łatwo jest to zrobić za pomocą jquery, przekazując odniesienie do pola powodującego zdarzenie onblur w „this”.
Na przykład

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

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

Dzięki
Monika

Monika Sharma
źródło
-2

Możesz to zrobić tak:

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

Widzę tylko hacki w odpowiedziach, ale tak naprawdę istnieje bardzo łatwe w użyciu wbudowane rozwiązanie: Zasadniczo możesz przechwycić element skupienia w następujący sposób:

const focusedElement = document.activeElement

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

Thomas J.
źródło
Przynajmniej w moim przypadku to nie działa, ponieważ activeElement jest ciałem, jeśli sprawdzę to przy następnym renderowaniu / zaznaczeniu, to jest ustawione poprawnie. Wygląda jednak na to, że rozwiązanie shog9 jest jedynym właściwym rozwiązaniem, ponieważ zapewnia, że ​​tyknięcie zostało wprowadzone.
Mathijs Segers,