Pytanie Chrome (może Safari?) Dwukrotnie uruchamia "rozmycie" na polach wejściowych, gdy przeglądarka traci fokus


Oto interesujące jsfiddle.

W przeglądarce Firefox:

  1. Uruchom skrzypce
  2. Kliknij w polu tekstowym
  3. Kliknij gdzieś indziej. Powinien powiedzieć "1 rozmycie".
  4. Ponownie kliknij wejście tekstowe.
  5. ALT-TAB do innego okna. Fiddle powinien teraz powiedzieć "2 plamy".

W przeglądarce Chrome w kroku 5 jest napisane "3 plamy". Dwa oddzielne zdarzenia "rozmycia" są uruchamiane, gdy cała przeglądarka traci fokus. Jest to interesujące, ponieważ oznacza, że ​​nie można bezpiecznie założyć w procedurze "rozmycia", że element faktycznie miał fokus tuż przed wywołaniem zdarzenia; to znaczy, że utrata ostrości - przejście od "bycia w centrum zainteresowania" do "nieostry" - jest powodem tego wydarzenia. Gdy dwa Zdarzenia "rozmycia" są generowane, warunek ten nie jest spełniony podczas obsługi drugiego zdarzenia, ponieważ element jest już nieostry.

Czy to tylko błąd? Czy istnieje sposób na stwierdzenie, że zdarzenie "rozmycia" jest nieprawdziwe?


21
2018-03-10 20:34


pochodzenie


Zdarza się również, gdy naciskasz Tab, aby ustawić menu klucza, lub ustawiasz pasek adresu (zasadniczo skupiając wszystko poza stroną) ... Nie wydaje mi się to poprawne. - pimvdb
To jest pytanie dla google-chrome programiści nie Stackoverflow. (IMO) - gdoron
Cóż, @gdoron będzie prawdą, jeśli nikt nie będzie wiedział, jak wykryć nadmiarowe rozmycie lub jakoś temu zapobiec. Zgadzam się, że wydaje się mało prawdopodobne, aby było jakieś rozwiązanie, ale jest tu wielu inteligentnych ludzi :-) - Pointy
Wygląda na to, że nie dzieje się to w Safari. - pimvdb
@pimvdb ah ok bardzo dziękuję za sprawdzenie mnie :-) Nie mam Windows VM na komputerze, którego teraz używam, i wcale nie mam komputera Mac. Powinienem wypróbować przeglądarkę Android. - Pointy


Odpowiedzi:


Powód, dla którego jest uruchamiany dwa razy, jest spowodowany przez window.onblur. Zamazanie okna wyzwala zdarzenie blur we wszystkich elementach w tym oknie w ramach procesu przechwytywania / propagacji języka javascript. Wszystko, co musisz zrobić, to przetestować cel zdarzenia, ponieważ jest to okno.

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

Wcześniejsze http://jsfiddle.net/pDYsM/4/


18
2018-03-10 21:39



Nie jestem pewien, czy to naprawdę mniej skomplikowane, ale wydaje się, że to nie jest błąd. - Dagg Nabbit
Może to nie jest tak skomplikowane, że wydawało mi się, że to czyta. Edytuję moje oświadczenie, aby to odzwierciedlić. Tak, to nie jest błąd, to sposób, w jaki powinien działać. Inną zaletą mojej metody jest to, że jest ona całkowicie zgodna z przeglądarką. - Fresheyeball
Dlaczego używasz flagi i nie sprawdzasz, kto jest celem w rozmyciu? może to być o wiele prostsza odpowiedź. - gdoron
może to być dziwna rzecz jQuery, ale użycie samego .blur pokazuje cel jako "input" dwa razy. Hookowanie oddzielnej funkcji rozmycia okna to jedyny sposób, jaki znam, aby uzyskać ten cel. Musimy również upewnić się, że flaga jest resetowana w oknie focus, ponieważ nie możemy tego zrobić w niezawodny sposób w pliku input.blur. Może być na to lepsza droga niż flaga, ale nie udało mi się. - Fresheyeball
To ma sens, ale na pewno nie dzieje się tak w Firefoksie. Zastanawiam się, czy mogę sprawdzić cel wydarzenia ... - Pointy


To jest błąd przeglądarki Chrome. Zobacz Chromium Issue Tracker

Sposób obejścia jest w zaakceptowanej odpowiedzi.


3
2018-01-28 18:56





Pomiń drugie rozmycie:

var secondBlur = false;
this.onblur = function(){
    if(secondBlur)return;
    secondBlur = true;
    //do whatever
}
this.onfocus = function(){
    secondBlur = false;    
    //do whatever
}

2
2018-06-21 15:26



To bardzo wąskie rozwiązanie. Kto może powiedzieć, że dane wejściowe powinny być rozmyte tylko raz na całe życie strony? Co się stanie, jeśli użytkownik zaktualizuje dane wejściowe, karty, kliknie z powrotem, a następnie ponownie zaktualizuje i wyświetli kartę. - Ali Cheaito
Jak napisano, to rozwiązanie jest tak proste, jak i skuteczne. Będzie działać poprawnie w sytuacji opisywanej przez Ali Cheaito. - Ben Wheeler


To prawdopodobnie nie jest to, co chcesz usłyszeć, ale jedynym sposobem, aby to zrobić, wydaje się ręczne śledzenie, czy element jest skupiony, czy nie. Na przykład (Baw się tutaj):

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

Co ciekawe, nie mogłem uruchomić tego w jQuery (Baw się tutaj) ... Naprawdę nie używam jQuery, może robię coś nie tak tutaj?

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

Możesz także spróbować porównać cel wydarzenia z document.activeElement. Ten przykład zignoruje zdarzenia rozmycia z kartą alt + i rozmycie spowodowane kliknięciem na chrome ... chrome. Może to być przydatne w zależności od sytuacji. Jeśli użytkownik alt + zakładki z powrotem do Chrome, to tak, jakby pole nigdy nie straciło ostrości (skrzypce).

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
2018-03-10 20:59



Tak, to jest w zasadzie to, do czego wracałem, ale rodzi się pytanie, czy powinienem również zaufać zdarzeniu "focus" :-) - Pointy
@Pointy timeStamp takich podwójnych wydarzeń byłoby bardzo blisko, ale obawiam się, nie można na tym polegać. - kirilloid
@Pointy Założę się, że możesz zrobić coś w stylu CSS :focus hack, ale to brzmi jeszcze gorzej. - Dagg Nabbit
@GGG metoda czystego js włamie się w ie8-, ponieważ zdarzenia są window.event, zamiast być przekazywane do odpowiedniej funkcji. - Fresheyeball
@ Fresheyeball Tak, dobry punkt. Wiesz o tym i ja to wiem, a OP wie o tym, ale powinienem dodać to dla potomności. - Dagg Nabbit


Jestem w wersji Chrome 30.0.1599.101 m na Windows 7 i problem ten został naprawiony.


1
2017-10-18 17:58





Doświadczam tego samego i powyższe posty mają sens, dlaczego. W moim przypadku chciałem tylko wiedzieć, czy przynajmniej miało miejsce jedno zdarzenie rozmycia. W rezultacie okazało się, że właśnie wróciłem z funkcji "rozmycia", rozwiązałem problem i uniemożliwiłem wypalenie kolejnego zdarzenia.

   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
2017-12-06 07:24



ZA return w tym momencie funkcja nie ma żadnej różnicy, ponieważ funkcja w naturalny sposób powróci w tym momencie. - Pointy


Wygląda na to, że osobliwość angularjs daje prostsze rozwiązanie przy użyciu ng-blur; Obiekt zdarzenia $ jest zdefiniowany tylko wtedy, gdy przekażesz go:

ng-blur="onBlur($event)"

więc (jeśli nie używasz ng-blur w oknie) możesz sprawdzić:

$scope.onBlur = function( $event ) {
    if (event != undefined) {
       //this is the blur on the element
    }
}

1
2017-11-11 11:01