Quando ocorre um evento de "desfoque", como posso descobrir qual elemento o foco foi * para *?


187

Suponha que eu anexe uma blurfunção a uma caixa de entrada HTML como esta:

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

Existe uma maneira de obter o ID do elemento que causou o blurdisparo do evento (o elemento que foi clicado) dentro da função? Quão?

Por exemplo, suponha que eu tenha uma extensão como esta:

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

Se eu clicar no intervalo logo após o elemento de entrada ter o foco, ele perderá o foco. Como a função sabe mySpanque foi clicada?

PS: Se o evento onclick do span ocorresse antes do evento onblur do elemento de entrada, meu problema seria resolvido, porque eu poderia definir algum valor de status indicando que um elemento específico foi clicado.

PPS: O pano de fundo desse problema é que desejo acionar um controle de preenchimento automático AJAX externamente (a partir de um elemento clicável) para mostrar suas sugestões, sem que as sugestões desapareçam imediatamente devido ao blurevento no elemento de entrada. Então, eu quero verificar a blurfunção se um elemento específico foi clicado e, se sim, ignorar o evento de desfoque.


Essa é uma pergunta interessante que eu adoraria ver por trás do raciocínio - ou seja, por que você está fazendo isso? Qual é o contexto?
Rahul

Rahul e roosteronacid, atualizei a pergunta como uma reação aos seus comentários (o PPS).
Michiel Borkent 23/09/08

1
Como essas informações são um pouco antigas, veja aqui para obter uma resposta mais recente: stackoverflow.com/questions/7096120/…
Jonathan M

Respostas:


86

Hmm ... No Firefox, você pode usar explicitOriginalTargetpara puxar o elemento que foi clicado. Eu esperava toElementfazer o mesmo para o IE, mas ele não parece funcionar ... No entanto, você pode extrair o elemento recém-focado do 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" />

Advertência: Essa técnica não funciona para alterações de foco causadas pela tabulação de campos com o teclado e nem funciona no Chrome ou Safari. O grande problema com o uso activeElement(exceto no IE) é que ele não é consistentemente atualizado até após o blurevento foi processado e pode não ter valor válido durante todo o processamento! Isso pode ser atenuado com uma variação na técnica que Michiel acabou usando :

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

Isso deve funcionar nos navegadores mais modernos (testados no Chrome, IE e Firefox), com a ressalva de que o Chrome não concentra os botões nos quais são clicados (vs. tabulado para).


1
Há muito tempo que procuro algo como o explicativoOriginalTarget. Como você descobriu isso?
Kev

3
Examinou o objeto de evento no FireBug. FWIW, a propriedade é específica do Mozilla, e documentado em MDC: developer.mozilla.org/en/DOM/event.explicitOriginalTarget
Shog9

2
Isso não funciona (ou parou de funcionar?) No Firefox 3.6 e Safari 4.0.3 no Windows.
quer

1
@ Jonathan: a propriedade está disponível, mas não é atualizada quando o blurevento é acionado. Atualizei a resposta com detalhes. Você já tentou usar o activeElement para isso no Chrome ou Firefox? Dá-lhe o elemento fiquem desfocadas ...
Shog9

1
Na verdade, não está funcionando no FF 31: explícitaOriginalTarget mostra o destino de desfoque atual, document.activeElement é nulo no evento de desfoque.
Adrian Maire

75

Resposta 2015 : de acordo com os eventos da interface do usuário , você pode usar a relatedTargetpropriedade do evento:

Usado para identificar um secundário EventTargetrelacionado a um evento do Focus, dependendo do tipo de evento.

Para blureventos,

relatedTarget: destino do evento recebendo foco.

Exemplo:

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 O Firefox não suporta relatedTargetaté a versão 48 ( bug 962251 , MDN ).


O Firefox não tem apoio, mas há um bilhete: bugzilla.mozilla.org/show_bug.cgi?id=687787
Sandstrom

3
Agora tem. Veja aqui .
rplaurindo

amo a comunidade web, agora tudo é muito mais fácil ^ _ ^
am05mhz

6
Ótima solução. Infelizmente, relatedTargetretornará nullse o alvo que recebe o foco não for um elemento de entrada.
Pedro Hoehl Carvalho 15/09

5
Se receber elemento foco não é um elemento de entrada, adicione um tabIndex="0"atributo a ele e ele vai funcionar
Dany

19

Resolvi isso eventualmente com um tempo limite no evento onblur (graças ao conselho de um amigo que não é o StackOverflow):

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

Funciona tanto no FF quanto no IE.


9
Isso é considerado uma má prática no mundo javascript btw?
Michiel Borkent 24/09/08

1
post antigo, mas tenho a mesma pergunta. independentemente, é a única coisa que parece fazer o trabalho entre navegadores.
Joshs

esta resposta ajudou a minha TON resolvendo outro problema ... Obrigado Michael!
29410 Alex

@MichielBorkent, esta é uma implementação ruim porque não é orientada a eventos. Você espera um determinado período de tempo e espera que já tenha demorado o suficiente. Quanto mais você espera, mais seguro fica, mas também perde mais tempo se não precisar esperar tanto tempo. Talvez alguém esteja usando um dispositivo muito antigo / lento e esse tempo limite não seja suficiente. Infelizmente, estou aqui porque os eventos não estão me fornecendo o que preciso para determinar se um iframe está sendo clicado no FireFox, mas funciona para todos os outros navegadores. Estou tão tentado a usar esse método agora, mesmo que seja uma prática ruim.
CTS_AE 05/09/19

1
Esta questão é bastante antiga, remonta a 2008. Enquanto isso, pode ter havido melhores abordagens. Você pode tentar a resposta de 2015?
Michiel Borkent

16

É possível usar o evento mousedown do documento em vez do blur:

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

8

As FocusEventinstâncias de tipo têm relatedTargetatributo, no entanto, até a versão 47 do FF, especificamente, esse atributo retorna nulo, já que 48 já funciona.

Você pode ver mais aqui .


2

Também estou tentando fazer o Autocompleter ignorar a desfocagem se um elemento específico clicar e tiver uma solução funcional, mas apenas para o Firefox devido a explícitaOriginalTarget

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

Esse código envolve o método onBlur padrão do preenchimento automático e verifica se os parâmetros ignoreBlurEventElement estão definidos. se estiver definido, ele verifica sempre que o elemento clicado é ignoreBlurEventElement ou não. Se for, o preenchimento automático não chama onBlur; caso contrário, chama onBlur. O único problema é que ele só funciona no Firefox porque a propriedade explícitaOriginalTarget é específica do Mozilla. Agora estou tentando encontrar uma maneira diferente do uso explícitaOriginalTarget. A solução que você mencionou requer que você adicione o comportamento de onclick manualmente ao elemento. Se eu não conseguir resolver o problema explícitoOriginalTarget, acho que seguirei sua solução.


2

Você pode reverter o que está verificando e quando? Ou seja, se você se lembrar do que ficou embaçado pela última vez:

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

e, em seguida, no onClick do seu período, chame function () com os dois objetos:

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

Sua função pode decidir se deve ou não acionar o controle Ajax.AutoCompleter. A função possui o objeto clicado e o objeto desfocado. O onBlur já aconteceu e não fará com que as sugestões desapareçam.


1

Use algo como isto:

var myVar = null;

E então dentro da sua função:

myVar = fldID;

E depois:

setTimeout(setFocus,1000)

E depois:

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

Código 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

Eu acho que não é possibe, com o IE você pode tentar usar window.event.toElement, mas não funciona com o Firefox!


Não funciona com o Chrome ou o Safari. Talvez não funcione com novas versões do IE que são mais compatíveis com os padrões.
Robocat 26/05

1

Conforme observado nesta resposta , você pode verificar o valor de document.activeElement. documenté uma variável global, portanto você não precisa fazer mágica para usá-la no manipulador onBlur:

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

1
  • document.activeElement pode ser um nó pai (por exemplo, nó do corpo porque está em uma fase temporária, alternando de um destino para outro), portanto, não é utilizável para seu escopo
  • ev.explicitOriginalTarget nem sempre é valorizado

Portanto, a melhor maneira é usar o evento onclick on body para entender indiretamente que seu nó (event.target) está desfocado


1

Funciona no Google Chrome v66.x, Mozilla v59.x e Microsoft Edge ... Solution com jQuery.

Eu testo no Internet Explorer 9 e não é suportado.

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

Comente seu teste em outras versões do Internet Explorer.


0

Edit: Uma maneira hacky de fazer isso seria criar uma variável que controla o foco de todos os elementos importantes para você. Portanto, se você se importa com o foco perdido de 'myInput', defina uma variável para ele em foco.

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

Resposta original: Você pode passar 'this' para a função.

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

isso não responder à pergunta, espero que eu fiz isso mais claro com o exemplo adicional
Michiel Borkent

0

Sugiro usar variáveis ​​globais blurfrom e blurto. Em seguida, configure todos os elementos importantes para atribuir sua posição no DOM à variável blurfrom quando eles perderem o foco. Além disso, configure-os para que o ganho de foco defina a variável blurto para sua posição no DOM. Em seguida, você pode usar outra função para analisar os dados do blurfrom e blurto.


É quase a solução, mas no manipulador de eventos onblur eu já precisava saber em qual item foi clicado, então um tempo limite no onblur fez isso por mim.
Michiel Borkent 24/09/08

0

lembre-se de que a solução com explícitaOriginalTarget não funciona para saltos de entrada de texto em entrada de texto.

tente substituir os botões pelas seguintes entradas de texto e você verá a diferença:

<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

Joguei com esse mesmo recurso e descobri que o FF, IE, Chrome e Opera têm a capacidade de fornecer o elemento de origem de um evento. Eu não testei o Safari, mas acho que pode ter algo semelhante.

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

isso funciona bem porque voto negativo? basta remover originalEvent!
fekiri malek

0

Eu não gosto de usar o tempo limite ao codificar javascript, então eu faria isso da maneira oposta de Michiel Borkent. (Não tente o código por trás, mas você deve ter a ideia).

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

Na cabeça, algo assim

<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

Você pode corrigir o IE com:

 event.currentTarget.firstChild.ownerDocument.activeElement

Parece "explícitaOriginalTarget" para FF.

Antoine And J


0

Eu escrevi uma solução alternativa como tornar qualquer elemento focalizável e "desfocável".

Baseia-se em criar um elemento como, contentEditableocultar visualmente e desativar o próprio modo de edição:

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

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

DEMO

Nota: Testado no Chrome, Firefox e Safari (OS X). Não tenho certeza sobre o IE.


Relacionado: Eu estava procurando uma solução para VueJs; portanto, para aqueles que estão interessados ​​/ curiosos em como implementar essa funcionalidade usando a diretiva Vue Focusable, dê uma olhada .


-2

Deste jeito:

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

Ou se você anexar o ouvinte via JavaScript (jQuery neste exemplo):

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

Edit : desculpe. Eu interpretei mal a pergunta.


3
Se você está ciente de que essa não é a resposta para a pergunta e a interpretou mal, atualize-a de acordo ou exclua-a.
TJ

-2


Eu acho que é facilmente possível via jquery passando a referência do campo causando o evento onblur em "this".
Por exemplo

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

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

Graças
Monika


-2

Você poderia fazer assim:

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

-2

Vejo apenas hacks nas respostas, mas na verdade há uma solução embutida muito fácil de usar: Basicamente, você pode capturar o elemento de foco como este:

const focusedElement = document.activeElement

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


Pelo menos no meu caso, isso não funciona, pois o activeElement é o corpo, se eu verificar isso no próximo render / tick, ele está definido corretamente. Mas parece que a solução do shog9 é a única solução adequada, pois garante que um tique-taque esteja afetando.
Mathijs Segers
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.