Estou trabalhando em um site móvel que precisa funcionar em uma variedade de dispositivos. Os que estão me dando dor de cabeça no momento são BlackBerry.
Precisamos oferecer suporte a cliques no teclado e a eventos de toque.
Idealmente, eu apenas usaria:
$thing.click(function(){...})
mas o problema que estamos enfrentando é que alguns desses dispositivos blackberry têm um atraso muito irritante desde o momento do toque até o acionamento de um clique.
O remédio é usar o touchstart:
$thing.bind('touchstart', function(event){...})
Mas como faço para vincular os dois eventos, mas apenas disparar um? Ainda preciso do evento de clique para dispositivos de teclado, mas é claro que não quero que o evento de clique seja acionado se estiver usando um dispositivo de toque.
Uma pergunta bônus: existe alguma maneira de fazer isso e acomodar adicionalmente navegadores que nem sequer têm um evento de toque inicial? Ao pesquisar isso, parece que o BlackBerry OS5 não oferece suporte ao touchstart e também precisará contar com os eventos de clique desse navegador.
TERMO ADITIVO:
Talvez uma pergunta mais abrangente seja:
Com o jQuery, é possível / recomendado lidar com as interações de toque e de mouse com as mesmas ligações?
Idealmente, a resposta é sim. Caso contrário, tenho algumas opções:
1) Usamos o WURFL para obter informações sobre o dispositivo, para criar nossa própria matriz de dispositivos. Dependendo do dispositivo, usaremos o touchstart OU clique.
2) Detectar para suporte por toque no navegador via JS (preciso fazer mais pesquisas sobre isso, mas parece que isso é possível).
No entanto, isso ainda deixa um problema: e os dispositivos que suportam AMBOS. Alguns dos telefones suportados (nomeadamente o Nokias e BlackBerries) têm ecrãs tácteis e teclados. Então isso me leva de volta à pergunta original ... existe uma maneira de permitir as duas coisas de uma vez?
fonte
.bind('touchstart mouseup')
o resolverá (com base em um dos comentários abaixo)Respostas:
Atualização : Confira o projeto PolyFill de eventos do ponteiro do jQuery , que permite vincular a eventos de "ponteiro" em vez de escolher entre mouse e toque.
Associe-se a ambos, mas faça um sinalizador para que a função seja acionada apenas uma vez a cada 100ms.
fonte
click
alterá-lo paramousedown
... talvez o longo atraso seja a diferença entremousedown
emouseup
qual é a forma como aclick
é determinada.touchend
aplicando uma classe detouched
. Isso é acionado antes que o evento click seja chamado. Em seguida, adiciono um evento de clique que primeiro verifica a existência dessa classe. Se estiver lá, assumimos que os eventos de toque foram acionados e não fazemos nada com o clique, exceto remover o nome da classe para 'redefini-lo' para a próxima interação. Se a classe não estiver lá, assumimos que eles usaram um teclado para clicar no item e acionar a função a partir daí.Essa é a correção que eu "crio" e remove o GhostClick e implementa o FastClick. Experimente por conta própria e deixe-nos saber se funcionou para você.
fonte
event.handled
será igualundefined
sempre que o evento for disparado. Aqui está uma solução: defina o sinalizador 'manipulado' no próprio elemento de destino usandojQuery.data()
.event.stopPropagation();
e,event.preventDefault();
pelo meu entendimento (e teste), o evento só pode ser disparado uma vez com isso. então por que verificarif(event.handled !== true)
? Para mim, não é necessário ou sinto falta de algo?event.handled
ser verificado o valortrue
? Tanto quanto eu posso dizer, nuncafalse
. Começa comoundefined
e, em seguida, você deseja saber se foi definidotrue
.Você pode tentar algo como isto:
fonte
Geralmente isso também funciona:
fonte
Apenas adicionar
return false;
no final daon("click touchstart")
função de evento pode resolver esse problema.Na documentação do jQuery em .on ()
fonte
Eu tive que fazer algo semelhante. Aqui está uma versão simplificada do que funcionou para mim. Se um evento de toque for detectado, remova a ligação de clique.
No meu caso, o evento click foi vinculado a um
<a>
elemento, então tive que remover a ligação de clique e religar um evento de clique que impedia a ação padrão do<a>
elemento.fonte
Eu consegui da seguinte maneira.
Mole-mole...
fonte
e
parâmetrofunction()
Acredito que a melhor prática agora é usar:
EXEMPLO
EDIT (2017)
A partir de 2017, navegadores começando com o Chrome e dando passos para tornar o evento de clique
.on("click")
mais compatível para mouse e toque, eliminando o atraso gerado por eventos de toque nas solicitações de clique.Isso leva à conclusão de que voltar a usar apenas o evento click seria a solução mais simples para o futuro.
Ainda não fiz nenhum teste entre navegadores para ver se isso é prático.
fonte
mouseup
resultados imprevisíveis, especialmente ao usar um trackpad em vez de um mouse tradicional.Geralmente, você não deseja misturar a API de toque padrão e sem toque (clique). Depois de entrar no mundo do toque, é mais fácil lidar apenas com as funções relacionadas ao toque. Abaixo está um pseudo-código que faria o que você deseja.
Se você se conectar no evento touchmove e rastrear os locais, poderá adicionar mais itens na função doTouchLogic para detectar gestos e outros enfeites.
fonte
verifique botões rápidos e cliques de cliques no google https://developers.google.com/mobile/articles/fast_buttons
fonte
Bem ... Tudo isso é super complicado.
Se você tem modernizr, é um acéfalo.
fonte
Outra implementação para melhor manutenção. No entanto, essa técnica também fará event.stopPropagation (). O clique não é capturado em nenhum outro elemento que clicou por 100 ms.
fonte
Apenas para fins de documentação, eis o que eu fiz para a solução de clique / resposta mais rápida / mais rápida na área de trabalho / toque no celular que eu conseguia pensar:
Substituí a
on
função do jQuery por uma modificada que, sempre que o navegador suporta eventos de toque, substitui todos os meus eventos de clique por touchstart.O uso seria exatamente o mesmo de antes, como:
Mas usaria o touchstart quando disponível, clique quando não estiver. Não são necessários atrasos de qualquer tipo: D
fonte
Eu apenas tive a idéia de memorizar se
ontouchstart
alguma vez foi acionado. Nesse caso, estamos em um dispositivo que suporta e deseja ignorar oonclick
evento. Desdeontouchstart
sempre deve ser acionado antesonclick
, eu estou usando isso:fonte
Você pode tentar assim:
fonte
No meu caso, isso funcionou perfeitamente:
O principal problema foi quando, em vez disso, tentei com o clique, nos dispositivos de toque, acionar o clique e tocar ao mesmo tempo; se eu usar o clique, algumas funcionalidades não funcionavam em dispositivos móveis. O problema com o clique é que é um evento global que dispara o restante do evento, incluindo touchend.
fonte
Isso funcionou para mim, o celular ouve os dois, por isso evite o que é o evento de toque. a área de trabalho ouve apenas o mouse.
fonte
Sendo para mim a melhor resposta dada por Mottie, estou apenas tentando tornar seu código mais reutilizável, então esta é a minha contribuição:
fonte
Também estou trabalhando em um aplicativo da web Android / iPad, e parece que apenas o uso de "touchmove" é suficiente para "mover componentes" (não é necessário iniciar o touch). Ao desativar o touchstart, você pode usar .click (); do jQuery. Na verdade, está funcionando porque não foi sobrecarregado pelo touchstart.
Por fim, você pode binb .live ("touchstart", function (e) {e.stopPropagation ();}); para solicitar que o evento touchstart pare de se propagar, clique na sala () para ser acionado.
Funcionou para mim.
fonte
touchstart
?Há muitas coisas a considerar ao tentar resolver esse problema. A maioria das soluções interrompe a rolagem ou não trata os eventos de clique fantasma corretamente.
Para uma solução completa, consulte https://developers.google.com/mobile/articles/fast_buttons
NB: Você não pode manipular eventos de clique fantasma por elemento. Um clique atrasado é acionado pelo local da tela. Portanto, se seus eventos de toque modificarem a página de alguma forma, o evento de clique será enviado para a nova versão da página.
fonte
Pode ser eficaz atribuir aos eventos
'touchstart mousedown'
ou'touchend mouseup'
evitar efeitos colaterais indesejados do usoclick
.fonte
Aproveitando o fato de que um clique sempre segue um evento de toque, eis o que eu fiz para me livrar do "clique fantasma" sem precisar usar tempos limite ou sinalizadores globais.
Basicamente, sempre que um
ontouchstart
evento é acionado no elemento, um sinalizador é definido e, em seguida, removido (e ignorado) quando o clique chega.fonte
Por que não usar a API de eventos jQuery?
http://learn.jquery.com/events/event-extensions/
Eu usei esse evento simples com sucesso. É limpo, com espaço para nome e flexível o suficiente para melhorar.
fonte
Se você estiver usando jQuery, o seguinte funcionou muito bem para mim:
Outras soluções também são boas, mas eu estava vinculando vários eventos em um loop e precisava da função de auto-chamada para criar um fechamento apropriado. Além disso, eu não queria desativar a ligação, pois queria que ela pudesse ser invocada no próximo clique / toque inicial.
Pode ajudar alguém em situação semelhante!
fonte
Para recursos simples, basta reconhecer o toque ou clique em Eu uso o seguinte código:
Isso retornará "touch" se o evento touchstart estiver definido e "no touch", se não estiver. Como eu disse, essa é uma abordagem simples para eventos de clique / toque exatamente isso.
fonte
Estou tentando isso e até agora ele funciona (mas eu estou apenas no Android / Phonegap, então ressalte o emptor)
Não gosto do fato de estar vinculando manipuladores a cada toque, mas todas as coisas consideradas como toques não acontecem com muita frequência (no tempo do computador!)
Eu tenho um monte de manipuladores como o do '#keypad', por isso, ter uma função simples que me permite lidar com o problema sem muito código é o motivo pelo qual eu segui esse caminho.
fonte
Tente usar a
Virtual Mouse (vmouse) Bindings
partir dejQuery Mobile
. É um evento virtual especialmente para o seu caso:http://api.jquerymobile.com/vclick/
Lista de suporte do navegador: http://jquerymobile.com/browser-support/1.4/
fonte
EDIT: Minha resposta anterior (com base nas respostas deste tópico) não era o caminho a percorrer para mim. Eu queria um submenu para expandir a entrada do mouse ou tocar no clique e recolher na licença do mouse ou outro clique no toque. Como os eventos do mouse normalmente são acionados após os eventos de toque, era meio difícil escrever ouvintes de eventos que suportam a tela de toque e a entrada do mouse ao mesmo tempo.
plugin jQuery: toque ou mouse
Acabei escrevendo um plugin jQuery chamado " Touch Or Mouse " (897 bytes compactado) que pode detectar se um evento foi invocado por uma tela sensível ao toque ou mouse (sem testar o suporte ao toque!). Isso permite o suporte da tela sensível ao toque e do mouse ao mesmo tempo e separa completamente seus eventos.
Dessa forma, o OP pode usar
touchstart
outouchend
responder rapidamente a cliques de toque eclick
cliques invocados apenas por um mouse.Demonstração
Primeiro é preciso fazer ie. o elemento do corpo rastreia eventos de toque:
Os eventos do mouse são vinculados aos elementos da maneira padrão e, ao ligar
$body.touchOrMouse('get', e)
, podemos descobrir se o evento foi chamado por uma tela sensível ao toque ou mouse.Veja o plug-in no trabalho em http://jsfiddle.net/lmeurs/uo4069nh .
Explicação
touchstart
etouchend
eventos, dessa forma otouchend
evento não precisa ser disparado no elemento trigger (ou seja, um link ou botão). Entre esses dois eventos de toque, este plug-in considera qualquer evento de mouse invocado pelo toque.touchend
, quando um evento do mouse é disparado dentro deghostEventDelay
(opção, 1000ms por padrão) depoistouchend
, este plug-in considera que o evento do mouse é chamado pelo toque.:active
estado. Omouseleave
evento é acionado somente depois que o elemento perde esse estado por ie. clicando em outro elemento. Como isso pode levar alguns segundos (ou minutos!) Após omouseenter
evento ter sido disparado, esse plug-in acompanha o últimomouseenter
evento de um elemento : se o últimomouseenter
evento foi chamado pelo toque, omouseleave
evento a seguir também é considerado chamado pelo toque.fonte
Aqui está uma maneira simples de fazer isso:
Você basicamente salva o primeiro tipo de evento que é acionado na propriedade 'trigger' no objeto de dados do jQuery que está anexado ao documento raiz e só é executado quando o tipo de evento é igual ao valor em 'trigger'. Em dispositivos sensíveis ao toque, a cadeia de eventos provavelmente seria 'touchstart' seguida de 'clique'; no entanto, o manipulador 'click' não será executado porque "click" não corresponde ao tipo de evento inicial salvo em 'trigger' ("touchstart").
A suposição, e eu acredito que seja segura, é que o seu smartphone não mudará espontaneamente de um dispositivo de toque para um dispositivo de mouse ou a torneira nunca será registrada porque o tipo de evento 'trigger' é salvo apenas uma vez por o carregamento da página e o "clique" nunca corresponderiam a "toque inicial".
Aqui está um código de código com o qual você pode brincar (tente tocar no botão em um dispositivo de toque - não deve haver atraso no clique): http://codepen.io/thdoan/pen/xVVrOZ
Também implementei isso como um plugin jQuery simples que também suporta a filtragem de descendentes do jQuery passando uma string de seletor:
Codepen: http://codepen.io/thdoan/pen/GZrBdo/
fonte
$.data()
para armazenar dados que podem ser acessados por várias funções e ainda não pertencem ao escopo global. Uma vantagem é que, como estou armazenando-o em um elemento, ele naturalmente me fornece mais contexto.O melhor método que encontrei é gravar o evento de toque e fazer com que o evento chame o evento de clique normal programaticamente. Dessa forma, você terá todos os seus eventos de clique normais e precisará adicionar apenas um manipulador de eventos para todos os eventos de toque. Para cada nó que você deseja tornar tocável, basta adicionar a classe "touchable" a ele para chamar o manipulador de toque. Com o Jquery, funciona dessa maneira com alguma lógica para garantir que seja um evento de toque real e não um falso positivo.
fonte