Qual é a melhor maneira de detectar um dispositivo 'touch screen' usando JavaScript?

416

Eu escrevi um plug-in jQuery para uso em computadores e dispositivos móveis. Gostaria de saber se existe uma maneira com JavaScript para detectar se o dispositivo tem capacidade de tela de toque. Estou usando o jquery-mobile.js para detectar os eventos da tela de toque e funciona no iOS, Android etc., mas também gostaria de escrever instruções condicionais com base no fato de o dispositivo do usuário ter uma tela de toque.

Isso é possível?

screenm0nkey
fonte
esta é a melhor maneira var x = 'touchstart' em document.documentElement; console.log (x) // return true se for suportado // else return false
Risa__B
Por que esse segmento é protegido se novas técnicas ainda estão surgindo?
Andy Hoffman

Respostas:

139

Atualização: Leia a resposta do blmstr abaixo antes de colocar uma biblioteca de detecção de recursos inteira em seu projeto. Detectar o suporte ao toque real é mais complexo, e o Modernizr cobre apenas um caso de uso básico.

O Modernizr é uma maneira excelente e leve de realizar todos os tipos de detecção de recursos em qualquer site.

Ele simplesmente adiciona classes ao elemento html para cada recurso.

Você pode segmentar esses recursos facilmente em CSS e JS. Por exemplo:

html.touch div {
    width: 480px;
}

html.no-touch div {
    width: auto;
}

E Javascript (exemplo jQuery):

$('html.touch #popup').hide();
Alan Christopher Thomas
fonte
88
O Modernizr não testa telas sensíveis ao toque. Ele testa a existência de eventos de toque no navegador. Consulte a seção "Testes diversos" nos documentos: modernizr.com/docs/#features-misc
Harry Love
1
você também pode fazer um teste de JS para a existência de eventos de toque if (Modernizr.touch) {/ * fazer contato coisas /} else {/ bem, não * /}
Anatoly G
7
Para o argumento de @ harrylove, desde que o Windows 8 foi lançado, o Modernizr retornou incorretamente todos os navegadores do meu PC como compatíveis com o toque.
Anton
3
Atualização: a resposta do blmstr é melhor e é uma solução Javascript pura.
Alan Christopher Thomas
1
Se Modernizr.touchretornar inesperadamente undefined, você pode ter um Modernizr personalizado (você pode escolher) sem suporte para a detecção de eventos por toque.
Henrik N
680

Você já tentou usar esta função? (É o mesmo que o Modernizr costumava usar.)

function is_touch_device() {  
  try {  
    document.createEvent("TouchEvent");  
    return true;  
  } catch (e) {  
    return false;  
  }  
}

console.log(is_touch_device());

ATUALIZAÇÃO 1

document.createEvent("TouchEvent")começaram a retornar trueno cromo mais recente (v. 17). Modernizr atualizou isso há um tempo atrás. Confira o teste Modernizr aqui .

Atualize sua função assim para fazê-la funcionar:

function is_touch_device1() {
  return 'ontouchstart' in window;
}

console.log(is_touch_device1());

ATUALIZAÇÃO 2

Eu descobri que o acima não estava funcionando no IE10 (retornando false no MS Surface). Aqui está a correção:

function is_touch_device2() {
  return 'ontouchstart' in window        // works on most browsers 
  || 'onmsgesturechange' in window;  // works on IE10 with some false positives
};

console.log(is_touch_device2());

ATUALIZAÇÃO 3

'onmsgesturechange' in windowretornará true em algumas versões de desktop do IE, portanto isso não é confiável. Isso funciona de maneira um pouco mais confiável:

function is_touch_device3() {
  return !!('ontouchstart' in window        // works on most browsers 
  || navigator.maxTouchPoints);       // works on IE10/11 and Surface
};

console.log(is_touch_device3());

ATUALIZAÇÃO 2018

O tempo passa e existem novas e melhores maneiras de testar isso. Basicamente, extraí e simplifiquei a maneira como o Modernizr verificou:

function is_touch_device4() {
    
    var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
    
    var mq = function (query) {
        return window.matchMedia(query).matches;
    }

    if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
        return true;
    }

    // include the 'heartz' as a way to have a non matching MQ to help terminate the join
    // https://git.io/vznFH
    var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
    return mq(query);
}

console.log(is_touch_device4());

Aqui eles estão usando o touch-enabledrecurso de consulta de mídia não padrão , que eu acho meio estranho e uma prática ruim. Mas ei, no mundo real, acho que funciona. No futuro (quando suportados por todos), esses recursos de consulta de mídia poderão fornecer os mesmos resultados: pointere hover.

Confira a fonte de como o Modernizr está fazendo isso .

Para um bom artigo que explica os problemas com a detecção por toque, consulte: Stu Cox: você não pode detectar uma tela sensível ao toque .

bolmaster2
fonte
20
O double bang lança um valor para um booleano, forçando a função a retornar um trueou false. Você pode ler mais sobre isso aqui: stackoverflow.com/questions/4686583/…
Rob Flaherty
2
Isso não funciona com o Opera Mobile 10 ou o Internet Explorer Mobile 6 (Windows Mobile 6.5).
doubleJ
17
O duplo NOT (!!) é supérfluo, pois o inoperador já avalia como um booleano.
Steve
11
'onmsgesturechange'está avaliando a verdade mesmo em dispositivos sem toque (PC). window.navigator.msMaxTouchPointsparece ser mais preciso. Encontrei aqui .
Steve
6
Ele está sendo avaliado como verdadeiro no IE10 no Windows 8, mesmo que minha tela não tenha sensores de toque. Eu atualizei meu velho laptop do Windows 7 para o Windows 8.
Pwner
120

Como o Modernizr não detecta o IE10 no Windows Phone 8 / WinRT, uma solução simples para vários navegadores é:

var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

Você só precisa verificar uma vez, pois o dispositivo não oferece suporte repentino ou não ao toque; basta armazená-lo em uma variável para poder usá-lo várias vezes com mais eficiência.

Matt Stow
fonte
3
'onmsgesturechange' na janela também detecta o IE10 "desktop" em dispositivos sem toque, portanto, esse não é um método confiável para determinar o toque.
quer
6
Essa resposta deveria ter sido aceita, pois é a melhor e mais simples e atualizada. Em uma função, acredito que isso seria mais consistente: return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);(para combinar as duas respostas) Também funciona bem no IE10!
Yeti
Essa deve ser a resposta aceita. 'onmsgesturechange' in windowretorna true no desktop IE10 mesmo quando o toque é possível
Sam Thornton
6
Tudo que você precisa:function isTouchDevice() { return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);}
GFoley83 4/13
1
Até a sugestão de GFoleys de 'ontouchstart' na janela || !! (navigator.msMaxTouchPoints); retornos Fals positiva no Chrome 30 dev fevereiro de 2014.
Tom Andersen
37

Usando todos os comentários acima, montei o seguinte código que funciona para minhas necessidades:

var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));

Eu testei isso no iPad, Android (navegador e Chrome), Blackberry Playbook, iPhone 4s, Windows Phone 8, IE 10, IE 8, IE 10 (Windows 8 com tela sensível ao toque), Opera, Chrome e Firefox.

Atualmente, ele falha no Windows Phone 7 e ainda não consegui encontrar uma solução para esse navegador.

Espero que alguém ache isso útil.

David
fonte
Existe algum motivo para você não usar: function is_touch_device () {return !! ('ontouchstart' na janela) || !! ('msmaxtouchpoints' no navegador); };
sidonaldson
o uso da função funcionará, mas geralmente gosto de usar o método da variável acima, para que seja testado apenas uma vez e seja mais rápido quando verifico mais tarde no meu código. Também descobri que precisava testar para ver se o msMaxTouchPoints era maior que 0, pois o IE 10 no Windows 8 sem uma tela de toque estava retornando 0 como msMaxTouchPoints.
David
retorna trueno meu Firefox 32 no windows 7 :(
vsync 27/11
O Firefox 33 e 33.1 no Windows 8 mostram falso corretamente no meu sistema. Se você atualizar o Firefox para a versão mais recente, ele ainda retornará verdadeiro? Você talvez tenha um dispositivo instalado em sua máquina que possa fazer o Firefox pensar incorretamente que sua máquina possui toque?
David
>>> 'ontouchstart' na janela >>> true FF 51.0.1 no ubuntu
Ravi Gadhia
25

Desde a introdução dos recursos de mídia de interação, você simplesmente pode:

if(window.matchMedia("(pointer: coarse)").matches) {
    // touchscreen
}

https://www.w3.org/TR/mediaqueries-4/#descdef-media-any-pointer

Atualização (devido aos comentários): A solução acima é detectar se um "ponteiro aproximado" - geralmente uma tela sensível ao toque - é o principal dispositivo de entrada. Caso deseje detectar se um dispositivo com, por exemplo, um mouse também possui uma tela sensível ao toque, você pode usar any-pointer: coarse.

Para obter mais informações, dê uma olhada aqui: Detectando que o navegador não possui mouse e é apenas de toque

Blackbam
fonte
3
Esta é de longe a melhor solução, obrigado! Embora eu recomendo usar (pointer: coarse)como você provavelmente está direcionando apenas a entrada principal. Pode ser usado na produção, pois os poucos navegadores não compatíveis são apenas para desktop. Há um ótimo artigo sobre isso em CSS-Tricks .
Fabian von Ellerts
2
Esta é a única solução que testei que funciona em todas as situações. Obrigado!
kaiserkiwi 20/02
20

Eu gosto deste:

function isTouchDevice(){
    return typeof window.ontouchstart !== 'undefined';
}

alert(isTouchDevice());
Benny Neugebauer
fonte
12
Não há necessidade de usar uma expressão ternária para retornar um booleano. Basta usar a expressão para retornar o booleano. function isTouchDevice(){ return (window.ontouchstart !== undefined); }
precisa
1
Você também pode usar: var isTouch = 'ontouchstart' in window;no entanto, isso não funciona com o Chrome mais recente (v31), var isTouch = 'createTouch' in window.document;ainda está funcionando.
Olivier
2
Como já mencionado nos comentários da pergunta anteriormente aceita. "O Modernizr não testa telas sensíveis ao toque. Testa a existência de eventos de toque no navegador". Sua função é tecnicamente hasTouchEvents () não isTouchDevice ()
hexalys
Observe que métodos semelhantes de teste touchstartfalharão ao reconhecer o Surface como um dispositivo de toque porque o IE usa pointereventos.
precisa
1
Talvez o @Nis esteja certo, mas no Firefox 39, ele retorne corretamente false.
Dan Dascalescu 15/07/2015
17

Se você usa o Modernizr , é muito fácil usar Modernizr.touchcomo mencionado anteriormente.

No entanto, prefiro usar uma combinação de Modernizr.touche teste de agente de usuário, apenas por segurança.

var deviceAgent = navigator.userAgent.toLowerCase();

var isTouchDevice = Modernizr.touch || 
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/)  || 
deviceAgent.match(/(iemobile)/) || 
deviceAgent.match(/iphone/i) || 
deviceAgent.match(/ipad/i) || 
deviceAgent.match(/ipod/i) || 
deviceAgent.match(/blackberry/i) || 
deviceAgent.match(/bada/i));

if (isTouchDevice) {
        //Do something touchy
    } else {
        //Can't touch this
    }

Se você não usa o Modernizr, pode simplesmente substituir a Modernizr.touchfunção acima por('ontouchstart' in document.documentElement)

Observe também que ao testar o agente do usuário, iemobilevocê terá uma gama mais ampla de dispositivos móveis Microsoft detectados do queWindows Phone .

Veja também esta pergunta do SO

Peter-Pan
fonte
8
Lotes de pontos de bônus para "fazer algo sensível" e "não pode tocar neste"
Lee Saxon
você está verificando várias vezes os mesmos dispositivos e fazendo vários regexes quando pode usar apenas um. além disso, você está fazendo expressões regulares que não diferenciam maiúsculas de minúsculas, mas a sequência já está em minúsculas.
perfil completo de Caesarsol
1
isso deve ser suficiente:/(iphone|ipod|ipad|android|iemobile|blackberry|bada)/.test(window.navigator.userAgent.toLowerCase())
caesarsol 19/10/16
Algum motivo para minúsculas ou fazer a correspondência não fazer distinção entre maiúsculas e minúsculas? Quando "iOS", "Android" ou "IEMobile" usariam outra caixa?
Henrik N
14

Tentamos a implementação modernizr, mas a detecção dos eventos de toque não é mais consistente (o IE 10 possui eventos de toque na área de trabalho do Windows, o IE 11 funciona, porque eles eliminaram os eventos de toque e adicionaram a API do ponteiro).

Decidimos otimizar o site como um site de toque, desde que não saibamos que tipo de entrada o usuário possui. Isso é mais confiável do que qualquer outra solução.

Nossas pesquisas dizem que a maioria dos usuários de desktop se move com o mouse sobre a tela antes de clicar, para que possamos detectá-los e alterar o comportamento antes que eles possam clicar ou passar o mouse sobre qualquer coisa.

Esta é uma versão simplificada do nosso código:

var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
    isTouch = false;
    window.removeEventListener('mousemove', mouseMoveDetector);
});
Martin Lantzsch
fonte
hoje os computadores possuem toque e mouse ... você deve se diferenciar. é uma necessidade absoluta saber se é apenas toque, mouse ou ambos. 3 estados diferentes.
vsync
1
Sim, você está certo, mas isso é muito difícil. Na melhor das hipóteses, seu aplicativo foi projetado para ser usado por qualquer controlador de entrada e não se importa se o usuário possui uma tela sensível ao toque, mouse, teclado ou todos juntos.
Martin Lantzsch
1
O comportamento do usuário vale mais do que uma informação real de que tipo de dispositivo o usuário possui. Quando você sabe que o usuário possui mouse, tela sensível ao toque e teclado - e daí? Lide com o comportamento (remoção do mouse, remoção de toque, pressionamento de tecla etc.). Os usuários podem alterar seu tipo de entrada no "tempo de execução", esse é um problema muito ruim quando você está desenvolvendo um aplicativo real usado 8 a 5 sem necessidade de recarga.
Martin Lantzsch 28/11
2
+1 Pragmaticamente, esta é a melhor resposta para mim. Por exemplo, eu tenho datagrids. Esses datagrids mostrarão um "ícone de edição" para tocar na edição ou um menu de contexto para mais opções. Se o movimento do mouse for detectado, removo o ícone (economiza espaço na grade) e os usuários podem clicar duas vezes ou clicar com o botão direito do mouse.
9288 programadormer
3
Chrome em dispositivos touch gatilhos mouseMove ocasionalmente
pstanton
9

Violino de trabalho

Eu consegui assim;

function isTouchDevice(){
    return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch);
}

if(isTouchDevice()===true) {
    alert('Touch Device'); //your logic for touch device
}
else {
    alert('Not a Touch Device'); //your logic for non touch device
}
Aamir Shahzad
fonte
não detecta o Windows Surface Tablet
Dan Beaulieu
@ DanBeaulieu, você pode ser específico para o dispositivo, porque eu tenho o windows phone para o qual está funcionando bem, também o usei no meu aplicativo, que é o controle de qualidade: ED, vou verificar novamente e atualizará a resposta. Desculpe pelo inconveniente
Aamir Shahzad
Não sei em que ano, é um profissional de superfície do Windows que pertence a um colega de trabalho. Depois de adicionar modernizr, conseguimos fazê-lo funcionar.
Dan Beaulieu
Isso relatou corretamente o Não toque na minha máquina com Windows 7 e toque em um laptop Windows 8 com tela sensível ao toque e um telefone Android 4.4 MotoX.
Clay Nichols
Dá um falso positivo no Chrome (46) no meu Mac
Patrick Fabrizius
9

Há algo melhor do que verificar se eles têm uma tela sensível ao toque, é verificar se eles estão usando, além disso, é mais fácil verificar.

if (window.addEventListener) {
    var once = false;
    window.addEventListener('touchstart', function(){
        if (!once) {
            once = true;
            // Do what you need for touch-screens only
        }
    });
}
Ivan Castellanos
fonte
6

Este funciona bem mesmo em tablets Windows Surface !!!

function detectTouchSupport {
msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
touchSupport = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch &&     document instanceof DocumentTouch);
if(touchSupport) {
    $("html").addClass("ci_touch");
}
else {
    $("html").addClass("ci_no_touch");
}
}
Sathiyamoorthy
fonte
4

Usei partes do código acima para detectar se o toque era exibido, para que meus iframes do fancybox aparecessem em computadores desktop e não no toque. Notei que o Opera Mini para Android 4.0 ainda estava sendo registrado como um dispositivo sem toque ao usar o código do blmstr sozinho. (Alguem sabe por quê?)

Acabei usando:

<script>
$(document).ready(function() {
    var ua = navigator.userAgent;
    function is_touch_device() { 
        try {  
            document.createEvent("TouchEvent");  
            return true;  
        } catch (e) {  
            return false;  
        }  
    }

    if ((is_touch_device()) || ua.match(/(iPhone|iPod|iPad)/) 
    || ua.match(/BlackBerry/) || ua.match(/Android/)) {
        // Touch browser
    } else {
        // Lightbox code
    }
});
</script>
Amado
fonte
você poderia explicar por que você não usa uma única chamada de correspondência com uma única regexp /iPhone|iPod|iPad|Android|BlackBerry/?
precisa saber é o seguinte
O Opera Mini realiza a renderização nos servidores do Opera e não no próprio dispositivo, por isso é meio estranho assim.
Bluesmoon
4

O maior problema na tentativa de detectar o toque está nos dispositivos híbridos que suportam o toque e o trackpad / mouse. Mesmo se você conseguir detectar corretamente se o dispositivo do usuário oferece suporte ao toque, o que você realmente precisa fazer é detectar qual dispositivo de entrada o usuário está usando no momento . Há uma descrição detalhada desse desafio e uma possível solução aqui .

Basicamente, a abordagem para descobrir se um usuário acabou de tocar na tela ou se usou um mouse / trackpad é registrar os eventos a touchstarte mouseoverna página:

document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first
document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover"

Uma ação de toque acionará esses dois eventos, embora o primeiro ( touchstart) sempre seja o primeiro na maioria dos dispositivos. Portanto, contando com essa sequência previsível de eventos, é possível criar um mecanismo que inclua ou remova dinamicamente uma can-touchclasse na raiz do documento para refletir o tipo de entrada atual do usuário neste momento no documento:

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")
     
    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }
     
    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }
     
    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

Mais detalhes aqui .

sopros de coco
fonte
3

Confira esta postagem , ele fornece um snippet de código muito bom sobre o que fazer quando dispositivos touch são detectados ou o que fazer se o evento touchstart for chamado:

$(function(){
  if(window.Touch) {
    touch_detect.auto_detected();
  } else {
    document.ontouchstart = touch_detect.surface;
  }
}); // End loaded jQuery
var touch_detect = {
  auto_detected: function(event){
    /* add everything you want to do onLoad here (eg. activating hover controls) */
    alert('this was auto detected');
    activateTouchArea();
  },
  surface: function(event){
    /* add everything you want to do ontouchstart here (eg. drag & drop) - you can fire this in both places */
    alert('this was detected by touching');
    activateTouchArea();
  }
}; // touch_detect
function activateTouchArea(){
  /* make sure our screen doesn't scroll when we move the "touchable area" */
  var element = document.getElementById('element_id');
  element.addEventListener("touchstart", touchStart, false);
}
function touchStart(event) {
  /* modularize preventing the default behavior so we can use it again */
  event.preventDefault();
}
Safran Ali
fonte
3

Eu evitaria usar a largura da tela para determinar se um dispositivo é um dispositivo de toque. Existem telas sensíveis ao toque muito maiores que 699px, pense no Windows 8. Navigatior.userAgent pode ser bom substituir mensagens falsas.

Eu recomendaria verificar esta questão no Modernizr.

Você deseja testar se o dispositivo suporta eventos de toque ou é um dispositivo de toque. Infelizmente, isso não é a mesma coisa.

híbrido
fonte
3

Não, não é possível. As excelentes respostas dadas são sempre parciais, porque qualquer método determinado produzirá falsos positivos e falsos negativos. Mesmo o navegador nem sempre sabe se uma tela sensível ao toque está presente, devido às APIs do SO, e o fato pode mudar durante uma sessão do navegador, principalmente com disposições do tipo KVM.

Veja mais detalhes neste excelente artigo:

http://www.stucox.com/blog/you-cant-detect-a-touchscreen/

O artigo sugere que você reconsidere as suposições que fazem você querer detectar telas sensíveis ao toque; elas provavelmente estão erradas. (Eu verifiquei o meu próprio aplicativo e minhas suposições estavam realmente erradas!)

O artigo conclui:

Para layouts, suponha que todos tenham uma tela sensível ao toque. Os usuários de mouse podem usar controles de interface do usuário grandes com muito mais facilidade do que os usuários de toque podem usar os pequenos. O mesmo vale para os estados de foco.

Para eventos e interações, suponha que alguém possa ter uma tela sensível ao toque. Implemente interações de teclado, mouse e toque, garantindo que nenhum bloqueie um ao outro.

Dave Burt
fonte
3

Muitos desses trabalhos, mas requerem jQuery ou linters javascript, reclamam da sintaxe. Considerando que sua pergunta inicial pede uma maneira "JavaScript" (não jQuery, não Modernizr) de resolver isso, aqui está uma função simples que funciona sempre. Também é o mínimo possível.

function isTouchDevice() {
    return !!window.ontouchstart;
}

console.log(isTouchDevice());

Um último benefício que mencionarei é que esse código é independente da estrutura e do dispositivo. Aproveitar!

seanforyou23
fonte
function isTouchScreen() { return window.matchMedia('(hover: none)').matches;}Isso funcionou para mim, por isso estou adicionando uma contribuição a essa resposta, pois também esperava um encadeamento de baunilha JS quando o Google me trouxe aqui.
Daniel Lavedonio de Lima
2

Parece que o Chrome 24 agora suporta eventos de toque, provavelmente para Windows 8. Portanto, o código postado aqui não funciona mais. Em vez de tentar detectar se o toque é suportado pelo navegador, agora estou vinculando os eventos de toque e clique e certificando-me de que apenas um seja chamado:

myCustomBind = function(controlName, callback) {

  $(controlName).bind('touchend click', function(e) {
    e.stopPropagation();
    e.preventDefault();

    callback.call();
  });
};

E então chamando:

myCustomBind('#mnuRealtime', function () { ... });

Espero que isto ajude !

wizmagister
fonte
1
Thread relacionado, stackoverflow.com/questions/12566306/…
Air
2

Todos os navegadores suportados, exceto o Firefox para desktop, sempre TRUE por causa do design responsivo do Firefox para desktop, mesmo que você clique no botão sensível ao toque ou não!

Espero que a Mozilla conserte isso na próxima versão.

Estou usando o Firefox 28 desktop.

function isTouch()
{
    return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}
xicooc
fonte
ainda é a versão 32.0 e ainda não o corrigiram! insano. por que isso não pode ser alternado? Isso sempre retorna true:(
vsync
2

jQuery v1.11.3

Há muitas informações boas nas respostas fornecidas. Recentemente, porém, passei muito tempo tentando vincular tudo a uma solução de trabalho para realizar duas coisas:

  1. Detecte que o dispositivo em uso é um dispositivo do tipo tela de toque.
  2. Detecte que o dispositivo foi tocado.

Além deste post e Detectando dispositivos de tela de toque com Javascript , achei este post de Patrick Lauke extremamente útil: https://hacks.mozilla.org/2013/04//detecting-touch-its-the-why-not-the-how /

Aqui está o código ...

$(document).ready(function() {
//The page is "ready" and the document can be manipulated.

    if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0))
    {
      //If the device is a touch capable device, then...
      $(document).on("touchstart", "a", function() {

        //Do something on tap.

      });
    }
    else
    {
      null;
    }
});

Importante! o*.on( events [, selector ] [, data ], handler ) método precisa ter um seletor, geralmente um elemento, que possa manipular o evento "touchstart" ou qualquer outro evento semelhante associado a toques. Nesse caso, é o elemento de hiperlink "a".

Agora, você não precisa manipular o clique normal do mouse em JavaScript, porque você pode usar CSS para manipular esses eventos usando seletores para o elemento "a" do hiperlink, assim:

/* unvisited link */
a:link 
{

}

/* visited link */
a:visited 
{

}

/* mouse over link */
a:hover 
{

}

/* selected link */
a:active 
{

}

Nota: Existem outros seletores também ...

serge-k
fonte
1
var isTouchScreen = 'createTouch' in document;

ou

var isTouchScreen = 'createTouch' in document || screen.width <= 699 || 
    ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) || 
    ua.match(/Android/);

seria uma verificação mais completa, suponho.

samuel segal
fonte
3
Seria bom notar que uase refere navigator.userAgent. Além disso, a detecção pela largura da tela pode dar um resultado falso se alguém abrir um navegador no modo não em tela cheia.
51111 HoLyVieR
1

Eu uso:

if(jQuery.support.touch){
    alert('Touch enabled');
}

no jQuery mobile 1.0.1

Marca
fonte
1

Também lutei bastante com diferentes opções sobre como detectar em Javascript se a página é exibida em um dispositivo com tela de toque ou não. A IMO, a partir de agora, não existe uma opção real para detectar a opção corretamente. Os navegadores relatam eventos de toque em máquinas de desktop (porque o sistema operacional talvez esteja pronto para toque) ou algumas soluções não funcionam em todos os dispositivos móveis.

No final, percebi que estava seguindo a abordagem errada desde o início: se minha página fosse semelhante em dispositivos de toque e sem toque, talvez eu não devesse me preocupar em detectar a propriedade: meu cenário era desativar dicas de ferramentas sobre botões em dispositivos de toque, pois levam a toques duplos nos quais eu queria um único toque para ativar o botão.

Minha solução foi refatorar a visualização para que nenhuma dica de ferramenta fosse necessária sobre um botão e, no final, não precisei detectar o dispositivo de toque do Javascript com métodos que todos têm suas desvantagens .

Michael
fonte
1

Você pode instalar o modernizador e usar um evento de toque simples. Isso é muito eficaz e funciona em todos os dispositivos que eu testei, inclusive na superfície do Windows!

Eu criei um jsFiddle

function isTouchDevice(){
    if(Modernizr.hasEvent('touchstart') || navigator.userAgent.search(/Touch/i) != -1){
         alert("is touch");
            return true;
         }else{
            alert("is not touch");
            return false;
    }
}
Endjeechner
fonte
3
Bem-vindo ao SO! O código por si só (como código não comentado) raramente constitui uma resposta. Você pode melhorar esta resposta adicionando uma explicação do trecho.
ebarr
1

A resposta prática parece ser aquela que considera o contexto:

1) Site público (sem login)
Codifique a interface do usuário para trabalhar com as duas opções juntas.

2) Site de logon
Capture se um movimento do mouse ocorreu no formulário de logon e salve-o em uma entrada oculta. O valor é passado com as credenciais de login e adicionado à sessão do usuário , para que possa ser usado durante toda a duração da sessão.

Jquery para adicionar apenas à página de login:

$('#istouch').val(1); // <-- value will be submitted with login form

if (window.addEventListener) {
    window.addEventListener('mousemove', function mouseMoveListener(){
        // Update hidden input value to false, and stop listening
        $('#istouch').val(0); 
        window.removeEventListener('mousemove', mouseMoveListener);
    });
} 

(+1 para @Dave Burt e +1 para @Martin Lantzsch em suas respostas)

programador
fonte
1

O problema

Devido a dispositivos híbridos que usam uma combinação de toque e entrada de mouse, você precisa poder alterar dinamicamente o estado / variável que controla se um trecho de código deve ser executado se o usuário é um usuário de toque ou não.

Os dispositivos de toque também são acionados mousemovena torneira.

Solução

  1. Suponha que o toque seja falso ao carregar.
  2. Aguarde até que um touchstartevento seja disparado e defina-o como verdadeiro.
  3. Se o touchstart foi acionado, adicione um manipulador de remoção de mouse.
  4. Se o tempo entre o disparo de dois eventos de remoção de mouse foi menor que 20ms, suponha que eles estejam usando um mouse como entrada. Remova o evento, pois ele não é mais necessário e o mouse é um evento caro para dispositivos de mouse.
  5. Assim que o touchstart é acionado novamente (o usuário voltou a usar o touch), a variável é configurada novamente como true. E repita o processo para que seja determinado de forma dinâmica. Se, por algum milagre, a mousemove é acionada duas vezes ao toque absurdamente rapidamente (nos meus testes é praticamente impossível fazê-lo dentro de 20ms), o próximo touchstart voltará a ser verdadeiro.

Testado no Safari iOS e Chrome para Android.

Nota: não tem 100% de certeza nos eventos do ponteiro para o MS Surface, etc.

Codepen demo


const supportsTouch = 'ontouchstart' in window;
let isUsingTouch = false;

// `touchstart`, `pointerdown`
const touchHandler = () => {
  isUsingTouch = true;
  document.addEventListener('mousemove', mousemoveHandler);
};

// use a simple closure to store previous time as internal state
const mousemoveHandler = (() => {
  let time;

  return () => {
    const now = performance.now();

    if (now - time < 20) {
      isUsingTouch = false;
      document.removeEventListener('mousemove', mousemoveHandler);
    }

    time = now;
  }
})();

// add listeners
if (supportsTouch) {
  document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints || navigator.msMaxTouchPoints) {
  document.addEventListener('pointerdown', touchHandler);
}
gelado
fonte
1

Na verdade, pesquisei essa questão e considero todas as situações. porque também é um grande problema no meu projeto. Então, chego à função abaixo, que funciona para todas as versões de todos os navegadores em todos os dispositivos:

const isTouchDevice = () => {
  const prefixes = ['', '-webkit-', '-moz-', '-o-', '-ms-', ''];
  const mq = query => window.matchMedia(query).matches;

  if (
    'ontouchstart' in window ||
    (window.DocumentTouch && document instanceof DocumentTouch)
  ) {
    return true;
  }
  return mq(['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''));
};

Dica : Definitivamente, oisTouchDevicejust retornabooleanvalores.

AmerllicA
fonte
0

supportObjeto jQuery de extensão :

jQuery.support.touch = 'ontouchend' in document;

E agora você pode verificá-lo em qualquer lugar, assim:

if( jQuery.support.touch )
   // do touch stuff
vsync
fonte
0

Isso parece estar funcionando bem para mim até agora:

//Checks if a touch screen
is_touch_screen = 'ontouchstart' in document.documentElement;

if (is_touch_screen) {
  // Do something if a touch screen
}
else {
  // Not a touch screen (i.e. desktop)
}
Lewis James-Odwin
fonte
0

Quando um mouse é conectado, pode-se supor com uma taxa de bits razoavelmente alta (eu diria praticamente 100%) que o usuário move o mouse pelo menos uma pequena distância após a página estar pronta - sem nenhum clique. O mecanismo abaixo detecta isso. Se detectado, considero isso um sinal de falta de suporte por toque ou, se suportado, de menor importância quando um mouse está em uso. O dispositivo de toque é assumido se não for detectado.

EDITAR Essa abordagem pode não atender a todos os propósitos. Ele pode ser usado para controlar a funcionalidade ativada com base na interação do usuário na página carregada, por exemplo, um visualizador de imagens. O código abaixo também deixará o evento mousemove vinculado a dispositivos sem mouse, como ele se destaca agora. Outras abordagens podem ser melhores.

Aproximadamente, é assim (desculpe pelo jQuery, mas semelhante em Javascript puro):

var mousedown, first, second = false;
var ticks = 10;
$(document).on('mousemove', (function(e) {
    if(UI.mousechecked) return;
    if(!first) {
        first = e.pageX;
        return;
        }
    if(!second && ticks-- === 0) {
        second = e.pageX;
        $(document).off('mousemove'); // or bind it to somewhat else
        }
    if(first  && second  && first !== second && !mousedown){
        // set whatever flags you want
        UI.hasmouse = true;
        UI.touch = false;
        UI.mousechecked = true;
    }

    return;
}));
$(document).one('mousedown', (function(e) {
    mousedown = true;
    return;
}));
$(document).one('mouseup', (function(e) {
    mousedown = false;
    return;
}));
cglow
fonte