Usando o jQuery para testar se uma entrada tem foco

561

Na primeira página de um site que estou construindo, vários <div>s usam a :hoverpseudo-classe CSS para adicionar uma borda quando o mouse está sobre eles. Um dos <div>s contém um <form>que, usando jQuery, manterá a borda se uma entrada dentro dela tiver foco. Isso funciona perfeitamente, exceto que o IE6 não suporta :hoveroutros elementos além de <a>s. Portanto, apenas para este navegador, estamos usando o jQuery para imitar o CSS :hoverusando o $(#element).hover()método O único problema é que, agora que o jQuery manipula o formulário focus() e hover() , quando uma entrada é focada, o usuário move o mouse para dentro e para fora, a borda desaparece.

Eu estava pensando que poderíamos usar algum tipo de condicional para interromper esse comportamento. Por exemplo, se testássemos o mouse se alguma das entradas tivesse foco, poderíamos impedir que a borda desaparecesse. AFAIK, não há :focusseletor no jQuery, portanto, não sei como fazer isso acontecer. Alguma ideia?

bloudermilk
fonte
1
você pode tentar resumir isso em algumas frases do que é necessário e do que estou acontecendo?
Mkoryak
Eu acho que você precisa olhar para capturar o foco e desfoque eventos ( docs.jquery.com/Events/focus e docs.jquery.com/Events/blur )
Wolfr
Postei uma resposta sobre a pergunta relacionada "Existe um 'foco' em JavaScript (ou jQuery)?" . Eu aprimorei [a abordagem cletus citada por gnarf] (# 2684561).
luiggitama

Respostas:

928

jQuery 1.6+

O jQuery adicionou um :focusseletor para que não precisemos mais adicioná-lo. Apenas use$("..").is(":focus")

jQuery 1.5 e abaixo

Edit: À medida que os tempos mudam, encontramos melhores métodos para testar o foco, o novo favorito é essa essência de Ben Alman :

jQuery.expr[':'].focus = function( elem ) {
  return elem === document.activeElement && ( elem.type || elem.href );
};

Citado de Mathias Bynens aqui :

Observe que o (elem.type || elem.href)teste foi adicionado para filtrar falsos positivos como corpo. Dessa forma, filtramos todos os elementos, exceto controles de formulário e hiperlinks.

Você está definindo um novo seletor. Veja Plugins / Criação . Então você pode fazer:

if ($("...").is(":focus")) {
  ...
}

ou:

$("input:focus").doStuff();

Qualquer jQuery

Se você apenas deseja descobrir qual elemento tem foco, pode usar

$(document.activeElement)

Se você não tem certeza se a versão será 1.6 ou inferior, você pode adicionar o :focusseletor se estiver ausente:

(function ( $ ) {
    var filters = $.expr[":"];
    if ( !filters.focus ) { 
        filters.focus = function( elem ) {
           return elem === document.activeElement && ( elem.type || elem.href );
        };
    }
})( jQuery );
gnarf
fonte
4
Isso pode causar falsos positivos. Consulte stackoverflow.com/questions/967096/… para obter mais informações (obrigado a Ben Alman e Diego Perini).
Mathias Bynens 22/03
@Mathias Bynens - Agradecimentos para a atualização (Você é mais que bem-vindos para editar esta resposta wiki comunidade btw!)
gnarf
E quando você precisa trabalhar com os modelos 1.5 e 1.6? Não quero substituir o próprio seletor de foco do jQuery. Algo como if (!jQuery.expr[':'].focus) { /* gist from Ben Alman */ }?
Betamos
@ betet - Exatamente certo ... Vou acrescentar algo à resposta para refletir isso.
precisa saber é
2
@ Alex - Por favor, forneça um caso de teste reduzido no jsFiddle mostrando o problema, porque, tanto quanto posso dizer, não há razão para que isso não deva funcionar com elementos "dinâmicos". Eu chamo travessuras ...
gnarf
46

CSS:

.focus {
    border-color:red;
}

JQuery:

  $(document).ready(function() {

    $('input').blur(function() {
        $('input').removeClass("focus");
      })
      .focus(function() {
        $(this).addClass("focus")
      });
  });
Daniel Moura
fonte
22

Aqui está uma resposta mais robusta que a atualmente aceita:

jQuery.expr[':'].focus = function(elem) {
  return elem === document.activeElement && (elem.type || elem.href);
};

Observe que o (elem.type || elem.href)teste foi adicionado para filtrar falsos positivos como body. Dessa forma, filtramos todos os elementos, exceto controles de formulário e hiperlinks.

(Extraído desta essência por Ben Alman .)

Mathias Bynens
fonte
13

Atualização de abril de 2015

Como essa pergunta já existe há algum tempo, e algumas novas convenções entraram em jogo, acho que devo mencionar que o .livemétodo foi depreciado.

Em seu lugar, o .onmétodo já foi introduzido.

A documentação deles é bastante útil para explicar como funciona;

O método .on () anexa manipuladores de eventos ao conjunto de elementos atualmente selecionado no objeto jQuery. A partir do jQuery 1.7, o método .on () fornece toda a funcionalidade necessária para anexar manipuladores de eventos. Para obter ajuda na conversão de métodos de eventos jQuery mais antigos, consulte .bind (), .delegate () e .live ().

Portanto, para você direcionar o evento 'focado na entrada', você pode usá-lo em um script. Algo como:

$('input').on("focus", function(){
   //do some stuff
});

Isso é bastante robusto e ainda permite que você use a tecla TAB também.

jbutler483
fonte
2

Não tenho certeza do que você está procurando, mas parece que isso pode ser alcançado armazenando o estado dos elementos de entrada (ou a div?) Como uma variável:

$('div').each(function(){

    var childInputHasFocus = false;

    $(this).hover(function(){
        if (childInputHasFocus) {
            // do something
        } else { }
    }, function() {
        if (childInputHasFocus) {
            // do something
        } else { }
    });

    $('input', this)
        .focus(function(){
            childInputHasFocus = true;
        })
        .blur(function(){
            childInputHasFocus = false;
        });
});
James
fonte
Foi isso que acabei fazendo, mas usei uma classe CSS arbitrária em vez de uma variável javascript global.
bloudermilk
Eu usei uma variação disso. Nenhum novo plugin jQuery é necessário. Isso me faz um campista feliz!
Dennis Day
1

Uma alternativa ao uso de classes para marcar o estado de um elemento é a funcionalidade interna de armazenamento de dados .

PS: Você é capaz de armazenar booleanos e o que quiser usando a data()função. Não se trata apenas de strings :)

$("...").mouseover(function ()
{
    // store state on element
}).mouseout(function ()
{
    // remove stored state on element
});

E então é apenas uma questão de acessar o estado dos elementos.

cllpse
fonte
1

Você já pensou em usar o mouseOver e o mouseOut para simular isso. Veja também mouseEnter e mouseLeave

mkoryak
fonte
Isso é essencialmente o que estou fazendo com o foco do jQuery. Você fornece duas funções, uma para entrada do mouse e outra para saída do mouse.
bloudermilk
0

Acompanhe os dois estados (focalizado, focado) como sinalizadores true / false e, sempre que um for alterado, execute uma função que remove a borda se ambos forem falsos, caso contrário, mostra a borda.

Portanto: onfocus define focalizado = verdadeiro, onblur define focalizado = falso. conjuntos onmouseover pairados = true, conjuntos onmouseover pairados = false. Após cada um desses eventos, execute uma função que adiciona / remove bordas.

Blixt
fonte
0

Tanto quanto eu sei, você não pode perguntar ao navegador se alguma entrada na tela tem foco, você precisa configurar algum tipo de rastreamento de foco.

Normalmente, tenho uma variável chamada "noFocus" e a defino como verdadeira. Em seguida, adiciono um evento de foco a todas as entradas que torna o noFocus falso. Em seguida, adiciono um evento de desfoque a todas as entradas que definem noFocus de volta à verdade.

Eu tenho uma classe MooTools que lida com isso facilmente, tenho certeza que você pode criar um plugin jquery para fazer o mesmo.

Depois de criado, você pode verificar o noFocus antes de fazer qualquer troca de borda.

Ryan Florence
fonte
0

Há um plugin para verificar se um elemento está focado: http://plugins.jquery.com/project/focused

$('input').each(function(){
   if ($(this) == $.focused()) {
      $(this).addClass('focused');
   }
})
Murat Çorlu
fonte
1
por que usar um plugin quando você pode apenas usar o Core Jquery?
Marcy Sutton
1
Você está certo. Mas eu não conhecia uma solução para esse problema há 2 anos.
Murat Çorlu
0

Eu tive um evento .live ("focus") definido para selecionar () (destacar) o conteúdo de uma entrada de texto, para que o usuário não precise selecioná-la antes de digitar um novo valor.

$ (formObj) .select ();

Por causa de peculiaridades entre diferentes navegadores, o select às vezes era substituído pelo clique que o causava e desmarcava o conteúdo logo depois em favor de colocar o cursor no campo de texto (funcionava normalmente no FF, mas falhava no IE)

Eu pensei que poderia resolver isso, colocando um pequeno atraso no select ...

setTimeout (function () {$ (formObj) .select ();}, 200);

Isso funcionou bem e a seleção persistiu, mas surgiu um problema engraçado. Se você tabulasse de um campo para o próximo, o foco mudaria para o próximo campo antes da seleção ocorrer. Como a seleção rouba o foco, o foco retornaria e acionaria um novo evento de "foco". Isso acabou em uma cascata de entradas selecionadas dançando por toda a tela.

Uma solução viável seria verificar se o campo ainda tem foco antes de executar o select (), mas como mencionado, não há uma maneira simples de verificar ... Acabei dispensando todo o destaque automático, em vez de mudar o que deveria ser uma única chamada jQuery select () em uma função enorme carregada de sub-rotinas ...

Brian
fonte
0

O que acabei fazendo é criar uma classe arbitrária chamada .elementhasfocus, que é adicionada e removida na função jQuery focus (). Quando a função hover () é executada com o mouse desligado, ela verifica .elementhasfocus:

if(!$("#quotebox").is(".boxhasfocus")) $(this).removeClass("box_border");

Portanto, se ela não tiver essa classe (leia-se: nenhum elemento dentro da div tem foco) a borda será removida. Caso contrário, nada acontece.

bloudermilk
fonte
-2

Simples

 <input type="text" /> 



 <script>
     $("input").focusin(function() {

    alert("I am in Focus");

     });
 </script>
Code Spy
fonte
Isso não indica qual elemento está atualmente em foco. É chamado quando um novo elemento obtém o foco. Portanto, se um elemento já tem o foco e você deseja saber se 'this' é esse, esse código é inútil.
Alexis Wilke