Estou desenvolvendo um aplicativo da Web (não um site com páginas de texto interessante) com uma interface muito diferente para toque (o dedo oculta a tela quando você clica) e o mouse (depende muito da visualização instantânea). Como posso detectar que meu usuário não tem mouse para apresentar a interface correta? Pretendo deixar uma opção para as pessoas com mouse e toque (como alguns notebooks).
O recurso de evento de toque no navegador não significa que o usuário esteja usando um dispositivo de toque (por exemplo, o Modernizr não o corta). O código que responde corretamente à pergunta deve retornar false se o dispositivo tiver um mouse, caso contrário, true. Para dispositivos com mouse e toque, ele deve retornar falso (não apenas tocar)
Como observação lateral, minha interface de toque também pode ser adequada para dispositivos apenas com teclado, por isso é mais a falta de mouse que estou procurando detectar.
Para tornar a necessidade mais clara, aqui está a API que estou procurando implementar:
// Level 1
// The current answers provide a way to do that.
hasTouch();
// Returns true if a mouse is expected.
// Note: as explained by the OP, this is not !hasTouch()
// I don't think we have this in the answers already, that why I offer a bounty
hasMouse();
// Level 2 (I don't think it's possible, but maybe I'm wrong, so why not asking)
// callback is called when the result of "hasTouch()" changes.
listenHasTouchChanges(callback);
// callback is called when the result of "hasMouse()" changes.
listenHasMouseChanges(callback);
fonte
Respostas:
O principal problema é que você possui as seguintes classes diferentes de dispositivos / casos de uso:
O pior é que é possível fazer a transição de algumas dessas classes para outras (conecta-se a um mouse, conecta-se ao teclado) ou um usuário pode parecer estar em um laptop normal até chegar e tocar na tela.
Você está certo ao supor que a presença de construtores de eventos no navegador não é uma boa maneira de avançar (e é um tanto inconsistente). Além disso, a menos que você esteja acompanhando um evento muito específico ou apenas tentando excluir algumas classes acima, usar os próprios eventos não é uma prova completa.
Por exemplo, digamos que você tenha descoberto que um usuário emitiu uma remoção de rato real (não a falsificada de eventos de toque, consulte http://www.html5rocks.com/en/mobile/touchandmouse/ ).
Então o que?
Você habilita estilos suspensos? Você adiciona mais botões?
De qualquer maneira, você está aumentando o tempo para o vidro, porque precisa esperar que um evento seja acionado.
Mas o que acontece quando o seu usuário nobre decide desconectar o mouse e entrar em contato direto com o usuário .. você espera que ele toque sua interface agora cheia e depois a altera logo que ele faz um esforço para identificar sua interface agora lotada?
Em forma de marcador, citando o stucox em https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101
Um aspecto à parte: o navegador sabe quando um usuário se conecta a um mouse / se conecta a um teclado, mas não o expõe ao JavaScript.
Isso deve levar você ao seguinte:
A idéia de aprimoramento progressivo se aplica muito bem aqui, no entanto. Crie uma experiência que funcione sem problemas, independentemente do contexto do usuário. Em seguida, faça suposições com base nos recursos do navegador / consultas de mídia para adicionar funcionalidades que serão relativas no contexto assumido. A presença de um mouse é apenas uma das inúmeras maneiras pelas quais diferentes usuários em diferentes dispositivos experimentam seu site. Crie algo com mérito no seu kernel e não se preocupe muito com a forma como as pessoas clicam nos botões.
fonte
:hover
elementos e coisas assim) quando o usuário alterna do mouse para o touch. Parece improvável que o usuário está usando o mouse + toque no momento exato o mesmo tempo (I média comoonn é como ter 2 mouses conectados ao mesmo computador hahaha)Que tal ouvir um evento de remoção de mouse no documento. Até ouvir esse evento, você assume que o dispositivo é apenas de toque ou teclado.
(Onde
listen
eunlisten
delegar paraaddEventListener
ouattachEvent
conforme apropriado.)Espero que isso não leve a muito jank visual, seria péssimo se você precisar de novos layouts massivos com base no modo ...
fonte
A partir de 2018, existe uma maneira boa e confiável de detectar se um navegador possui um mouse (ou dispositivo de entrada semelhante): recursos de interação de mídia CSS4 que agora são suportados por quase qualquer navegador moderno (exceto IE 11 e navegadores móveis especiais).
W3C:
Veja as seguintes opções:
As consultas de mídia também podem ser usadas em JS:
Palavras-chave:
Documentação do W3: https://www.w3.org/TR/mediaqueries-4/#mf-interaction
Suporte para navegador: https://caniuse.com/#search=media%20features
Problema semelhante: Detecte se um dispositivo cliente suporta os estados: hover e: focus
fonte
A resposta da @ Wyatt é ótima e nos dá muito o que pensar.
No meu caso, eu escolhi ouvir a primeira interação, só então definir um comportamento. Portanto, mesmo se o usuário tiver um mouse, tratarei como dispositivo de toque se a primeira interação foi um toque.
Considerando a ordem dada na qual os eventos são processados :
Podemos supor que, se o evento do mouse for acionado antes do toque, é um evento real do mouse, não um emulado. Exemplo (usando jQuery):
Isso funcionou para mim
fonte
Só é possível detectar se um navegador é capaz de tocar . Não há como saber se ele realmente possui uma tela de toque ou um mouse conectado.
Pode-se priorizar o uso ouvindo evento de toque em vez de evento de mouse se a capacidade de toque for detectada.
Para detectar o recurso de toque em vários navegadores:
Então pode-se usar isso para verificar:
ou para escolher qual evento escutar:
ou use abordagens separadas para toque versus não toque:
Para o mouse, é possível detectar apenas se o mouse está sendo usado, não se existe ou não. Pode-se configurar uma bandeira global para indicar que o mouse foi detectado pelo uso (semelhante a uma resposta existente, mas um pouco simplificada):
(não é possível incluir
mouseup
oumousedown
porque esse evento também pode ser acionado pelo toque)Navegadores restringe o acesso a APIs de sistema de baixo nível, necessárias para detectar recursos como recursos de hardware do sistema em que está sendo usado.
Existe a possibilidade de talvez escrever um plug-in / extensão para acessá-los, mas via JavaScript e DOM essa detecção é limitada para essa finalidade e seria necessário escrever um plug-in específico para as várias plataformas de SO.
Portanto, em conclusão: essa detecção só pode ser estimada por um "bom palpite".
fonte
Quando as consultas de mídia nível 4 estiver disponível nos navegadores, poderemos usar as consultas "ponteiro" e "pairar" para detectar dispositivos com um mouse.
Se realmente queremos comunicar essas informações para Javascript, poderíamos usar uma consulta CSS para definir estilos específicos de acordo com o tipo de dispositivo e, em seguida, usar
getComputedStyle
no Javascript para ler esse estilo e derivar dele o tipo de dispositivo original.Mas um mouse pode ser conectado ou desconectado a qualquer momento, e o usuário pode querer alternar entre o toque e o mouse. Portanto, talvez seja necessário detectar essa alteração e oferecer a alteração da interface ou fazê-lo automaticamente.
fonte
any-pointer
eany-hover
permitirá investigar todos os recursos aplicáveis do dispositivo. É bom dar uma olhada em como podemos resolver esse problema no futuro! :)Como você planeja oferecer uma maneira de alternar entre as interfaces de qualquer maneira, seria possível simplesmente pedir ao usuário que clique em um link ou botão para "inserir" a versão correta do aplicativo? Então você pode se lembrar da preferência deles por futuras visitas. Não é de alta tecnologia, mas é 100% confiável :-)
fonte
@SamuelRossille Infelizmente, nenhum navegador que eu saiba expor a existência (ou a falta dele) de um mouse.
Então, com isso dito, nós apenas temos que tentar fazer o melhor possível com a nossa opção existente ... eventos. Eu sei que não é exatamente o que você está procurando ... concordou que atualmente está longe de ser o ideal.
Podemos fazer o possível para descobrir se um usuário está usando um mouse ou toque a qualquer momento. Aqui está um exemplo rápido e sujo usando jQuery & Knockout:
Agora você pode vincular / assinar usingMouse () e usingTouch () e / ou estilizar sua interface com a classe body.mouse . A interface irá alternar assim que um cursor do mouse for detectado e no touchstart.
Esperamos ter em breve algumas opções melhores dos fornecedores de navegadores.
fonte
O Tera-WURFL pode informar os recursos do dispositivo que está visitando seu site , comparando a assinatura do navegador com o banco de dados. Dê uma olhada, é grátis!
fonte
Por que você simplesmente não detecta se ele tem a capacidade de detectar toques e / ou reagir aos movimentos do mouse?
fonte
has_touch = 'ontouchstart' in window
será suficiente, e assim por diante.Isso funcionou para mim em uma situação semelhante. Basicamente, suponha que o usuário não tenha um mouse até que você veja uma série curta de movimentos de rato consecutivos, sem interferir com mouse ou mouse. Não é muito elegante, mas funciona.
fonte
Dê uma olhada no modenizr, uma de suas características é o toque
http://modernizr.com/docs/#features-misc
Embora eu não tenha testado completamente, parece funcionar muito bem
Isso também está vinculado na página modernizr http://www.html5rocks.com/en/mobile/touchandmouse/
fonte
Como outros já apontaram, detectar definitivamente se eles têm ou não um mouse não é confiável. Isso pode mudar facilmente, dependendo do dispositivo. Definitivamente, é algo que você não pode fazer de forma confiável com um valor booleano verdadeiro ou falso, pelo menos em uma escala de documento.
Os eventos de toque e mouse são exclusivos. Portanto, isso pode ajudar um pouco na tomada de ações diferentes. O problema é que os eventos de toque estão mais próximos dos eventos de cima / baixo / movimento do mouse e também acionam um evento de clique.
Na sua pergunta, você diz que deseja passar o mouse para visualizar. Além disso, não conheço outros detalhes sobre sua interface. Estou assumindo que, com a falta de um mouse, você deseja que um toque seja visualizado, enquanto um clique executa uma ação diferente por causa da visualização instantânea.
Se for esse o caso, você pode adotar uma abordagem preguiçosa para a detecção:
Um evento onclick sempre será precedido por um evento onmouseover com o mouse. Portanto, anote que o mouse está sobre o elemento que foi clicado.
Você pode fazer isso com um evento onmousemove em todo o documento. Você pode usar
event.target
para registrar em qual elemento o mouse está localizado. Em seus eventos onclick, você pode verificar se o mouse está ou não sobre o elemento que está sendo clicado (ou um filho do elemento).A partir daí, você pode optar por confiar no evento click para ambos e executar uma ação A ou B, dependendo do resultado. A ação B pode ser nada se alguns dispositivos de toque não emitem um evento de clique (em vez disso, você teria que confiar nos eventos ontouch *).
fonte
Não acho que seja possível identificar um dispositivo apenas com toque (que eu saiba, é claro). O principal problema é que todos os eventos de mouse e teclado também são disparados por dispositivos de toque. Veja o exemplo a seguir, os dois alertas retornam true para dispositivos touch.
fonte
true
para'onmousedown' in window
A melhor ideia, na minha opinião, é o
mousemove
ouvinte (atualmente a melhor resposta). Eu acredito que esse método precisa ser um pouco modificado. É verdade que os navegadores baseados em toque simulam até o evento mousemove, como você pode ver nesta discussão do iOS , por isso devemos ter um pouco de cuidado.Faz sentido que os navegadores baseados em toque apenas emulem esse evento quando o usuário toca na tela (o dedo do usuário está pressionado). Isso significa que devemos adicionar um teste durante o manipulador do mouse para ver qual botão do mouse está pressionado (se houver) durante o evento. Se nenhum botão do mouse estiver pressionado, podemos assumir com segurança que um mouse real está presente. Se um botão do mouse estiver pressionado, o teste permanecerá inconclusivo.
Então, como isso seria implementado? Esta pergunta mostra que o método mais confiável para examinar qual botão do mouse está pressionado durante uma remoção de mouse é realmente escutar três eventos no nível do documento: remoção de mouse, remoção de mouse e mouse. A seta para cima e para baixo definirá apenas um sinalizador booleano global. A mudança fará o teste. Se você tiver um movimento e o booleano for falso, podemos assumir que um mouse está presente. Veja a pergunta para exemplos exatos de código.
Um comentário final. Esse teste não é ideal porque não pode ser executado em tempo de carregamento. Portanto, eu usaria um método de aprimoramento progressivo, conforme sugerido anteriormente. Por padrão, mostre uma versão que não suporta a interface de foco específico do mouse. Se um mouse for descoberto, ative esse modo em tempo de execução usando JS. Isso deve parecer o mais transparente possível para o usuário.
Para suportar alterações na configuração do usuário (ou seja, o mouse foi desconectado), você pode testar periodicamente. Embora eu acredite que seja melhor, neste caso, simplesmente notificar o usuário sobre os 2 modos e permitir que os usuários alternem manualmente entre eles (bem como a opção móvel / desktop, que sempre pode ser revertida).
fonte
Executei alguns testes em vários PCs, Linux, iPhone, telefones e guias Android. Estranho que não exista uma solução fácil à prova de balas. O problema surge quando alguns que possuem Touch e nenhum mouse ainda apresentam os eventos Touch e Mouse ao aplicativo. Como deseja suportar instâncias apenas com mouse e apenas com toque, deseja processar ambas, mas isso causa ocorrências duplas de interações do usuário. Se o mouse pode saber que o dispositivo não está presente no dispositivo, ele pode ignorar os eventos de mouse falso / inserido. Tentei definir sinalizador se MouseMove for encontrado, mas alguns navegadores lançam MouseMove falso, bem como MouseUp e MouseDown. Tentei examinar os registros de data e hora, mas achei que isso era muito arriscado. Conclusão: eu encontrei os navegadores que criavam os eventos de mouse falso sempre inseridos um único MouseMove antes da MouseDown inserida. Em 99,99% dos meus casos, ao executar em um sistema que possui um mouse real, há vários eventos MouseMove consecutivos - pelo menos dois. Portanto, controle se o sistema encontra dois eventos MouseMove consecutivos e declare que não há mouse presente se essa condição nunca for atendida. Provavelmente isso é muito simples, mas está funcionando em todas as minhas configurações de teste. Acho que vou continuar até encontrar uma solução melhor. - Jim W
fonte
Uma solução simples no jQuery para detectar o uso do mouse, que resolve o problema em que os dispositivos móveis também acionam o evento 'mousemove'. Basta adicionar um ouvinte do touchstart para remover o ouvinte do mousemove, para que ele não seja acionado ao tocar.
Obviamente, o dispositivo ainda pode ser touch AND mouse, mas o acima garante que um mouse real foi usado.
fonte
Acabei de encontrar uma solução que eu acho bastante elegante.
fonte
Corri para o mesmo problema, onde um único toque também foi registrado como um clique. Depois de ler os comentários das principais respostas votadas, criei minha própria solução:
O único problema que encontrei é que você precisa poder rolar para detectar corretamente um evento de toque. uma única guia (toque) pode causar problemas.
fonte
Passei horas descobrindo esse problema para o meu aplicativo Phonegap e criei esse hack. Ele gera um aviso do console se o evento acionado for um evento "passivo", o que significa que não aciona nenhuma alteração, mas funciona! Eu estaria interessado em alguma idéia para melhorar ou um método melhor. Mas isso efetivamente permite que eu use $ .touch () universalmente.
fonte
o principal problema que vejo aqui é que a maioria dos dispositivos de toque aciona um evento de mouse junto com o toque de resposta correspondente (touchstart -> mousedown, touchmove -> mousemove, etc.). Para apenas os teclados, finalmente os modernos, eles têm um navegador genérico, portanto você não consegue nem detectar a presença da classe MouseEvent.
A solução menos dolorosa aqui seria, na minha opinião, exibir um menu no lançamento (com gerenciamento 'alt' apenas para usuários do teclado) e talvez armazenar a opção com localStorage / cookies / serverside ou então manter a mesma escolha na próxima hora que o visitante chega.
fonte
Eu recomendo fortemente contra essa abordagem. Considere dispositivos com tela de toque e do tamanho de desktops e você tem um conjunto diferente de problemas para resolver.
Torne seu aplicativo utilizável sem o mouse (ou seja, sem visualização instantânea).
fonte
Gostaria de recomendar um script que me ajudou:
Eu tinha lido e tentado tudo o que era sugerido, sem resultados suficientes.
Então eu investiguei um pouco mais e encontrei este código - device.js
Estou usando isso no site do meu cliente, para detectar a existência do mouse:
(
<html>
deve terdesktop
classe) e parece muito bom, e paratouch
suporte, eu apenas faço a verificação regular'ontouchend' in document
e uso as informações de ambas as detecções para assumir uma coisa específica de que preciso.fonte
Geralmente, é uma idéia melhor detectar se a função de mouseover é suportada em vez de detectar o tipo de SO / navegador. Você pode fazer isso simplesmente da seguinte maneira:
Certifique-se de não fazer o seguinte:
Este último chamaria o método, em vez de verificar sua existência.
Você pode ler mais aqui: http://www.quirksmode.org/js/support.html
fonte