Jaki jest najlepszy sposób na wykrycie urządzenia z ekranem dotykowym za pomocą JavaScript?

416

Napisałem wtyczkę jQuery, która jest przeznaczona do użytku na komputerach i urządzeniach mobilnych. Zastanawiałem się, czy JavaScript umożliwia wykrycie, czy urządzenie ma funkcję ekranu dotykowego. Używam jquery-mobile.js do wykrywania zdarzeń na ekranie dotykowym i działa na iOS, Android itp., Ale chciałbym również napisać instrukcje warunkowe na podstawie tego, czy urządzenie użytkownika ma ekran dotykowy.

Czy to jest możliwe?

screenm0nkey
źródło
jest to lepszy sposób var x = 'touchstart' w document.documentElement; console.log (x) // zwróć wartość true, jeśli jest obsługiwana // zwróć wartość false
Risa__B,
Dlaczego ten wątek jest chroniony, jeśli wciąż pojawiają się nowe techniki?
Andy Hoffman,

Odpowiedzi:

139

Aktualizacja: Przed pobraniem całej biblioteki wykrywania funkcji do projektu przeczytaj odpowiedź blmstr poniżej. Wykrywanie faktycznej obsługi dotykowej jest bardziej złożone, a Modernizr obejmuje tylko podstawowy przypadek użycia.

Modernizr to świetny, lekki sposób na wykrywanie wszelkiego rodzaju funkcji w dowolnej witrynie.

Po prostu dodaje klasy do elementu HTML dla każdej funkcji.

Następnie możesz łatwo kierować te funkcje w CSS i JS. Na przykład:

html.touch div {
    width: 480px;
}

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

I JavaScript (przykład jQuery):

$('html.touch #popup').hide();
Alan Christopher Thomas
źródło
88
Modernizr nie testuje ekranów dotykowych. Sprawdza, czy w przeglądarce występują zdarzenia dotykowe. Zobacz sekcję „Różne testy” w dokumentacji: modernizr.com/docs/#features-misc
Harry Love
1
możesz również wykonać test JS na obecność zdarzeń dotykowych, jeśli (Modernizr.touch) {/ * wykonaj touch touch /} else {/ dobrze, nie * /}
Anatoly G
7
Do punktu @ harrylove, odkąd pojawił się Windows 8, Modernizr nieprawidłowo zwraca wszystkie przeglądarki mojego komputera PC jako kompatybilne z dotykiem.
Anton
3
Aktualizacja: odpowiedź blmstr jest lepsza i jest czystym rozwiązaniem Javascript.
Alan Christopher Thomas
1
Jeśli Modernizr.touchniespodziewanie powróci undefined, możesz mieć dostosowanego Modernizatora (możesz wybrać i wybrać) bez obsługi wykrywania zdarzeń dotykowych.
Henrik N
679

Próbowałeś użyć tej funkcji? (Jest to to samo, co używane przez Modernizr.)

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

console.log(is_touch_device());

AKTUALIZACJA 1

document.createEvent("TouchEvent")zaczęli wracać truew najnowszym chrome (v. 17). Modernizr zaktualizował to jakiś czas temu. Sprawdź test Modernizr tutaj .

Zaktualizuj swoją funkcję w ten sposób, aby działała:

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

console.log(is_touch_device1());

AKTUALIZACJA 2

Odkryłem, że powyższe nie działało na IE10 (zwracanie wartości false na MS Surface). Oto poprawka:

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

AKTUALIZACJA 3

'onmsgesturechange' in windowzwróci true w niektórych wersjach pulpitu IE, więc to nie jest niezawodne. Działa to nieco bardziej niezawodnie:

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

AKTUALIZACJA 2018

Czas płynie, a są nowe i lepsze sposoby na przetestowanie tego. Zasadniczo wyodrębniłem i uprościłem sposób sprawdzania przez Modernizr:

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

Tutaj używają niestandardowej touch-enabledfunkcji zapytania o media, co moim zdaniem jest dziwną i złą praktyką. Ale hej, w prawdziwym świecie myślę, że to działa. W przyszłości (gdy wszystkie będą obsługiwane) te funkcje zapytań o media mogą dać te same wyniki: pointeri hover.

Sprawdź źródło, w jaki sposób robi to Modernizr .

Dobry artykuł, który wyjaśnia problemy z wykrywaniem dotyku, zobacz: Stu Cox: Nie można wykryć ekranu dotykowego .

bolmaster2
źródło
20
Podwójny huk rzuca wartość na wartość logiczną, zmuszając funkcję do zwrócenia albo, truealbo false. Możesz przeczytać więcej na ten temat tutaj: stackoverflow.com/questions/4686583/…
Rob Flaherty
2
To nie działa z Opera Mobile 10 lub Internet Explorer Mobile 6 (Windows Mobile 6.5).
doubleJ
17
Podwójne NOT (!!) jest zbędne, ponieważ inoperator już ocenia na wartość logiczną.
Steve,
11
'onmsgesturechange'ocenia prawdę nawet w urządzeniach bezdotykowych (PC). window.navigator.msMaxTouchPointswydaje się być dokładniejszy. Znalazłem to tutaj .
Steve,
6
Sprawdza się jako prawda w IE10 na Windows 8, mimo że mój ekran nie ma czujników dotykowych.
Zaktualizowałem
120

Ponieważ Modernizr nie wykrywa IE10 na Windows Phone 8 / WinRT, proste rozwiązanie dla różnych przeglądarek to:

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

Trzeba tylko raz sprawdzić, ponieważ urządzenie nagle nie obsługuje lub nie obsługuje dotyku, więc po prostu zapisz go w zmiennej, aby móc używać go wiele razy bardziej wydajnie.

Matt Stow
źródło
3
„onmsgesturechange” w oknie wykrywa również „stacjonarny” IE10 na urządzeniach bezdotykowych, więc nie jest to niezawodna metoda określania dotyku.
Matt Stow,
6
Ta odpowiedź powinna zostać zaakceptowana, ponieważ jest najlepsza, najprostsza i aktualna. W funkcji uważam, że byłoby to bardziej spójne: return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);(aby połączyć obie odpowiedzi) Działa również dobrze w IE10!
Yeti
To powinna być zaakceptowana odpowiedź. 'onmsgesturechange' in windowzwraca true na pulpicie IE10, nawet jeśli dotyk jest możliwy
Sam Thornton
6
Wszystko czego potrzebujesz:function isTouchDevice() { return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);}
GFoley83
1
Nawet sugestia GFoleysa dotycząca „ontouchstart” w oknie || !! (navigator.msMaxTouchPoints); zwraca wartość Fals dodatnią w Chrome 30 Dev Lut 2014.
Tom Andersen
37

Korzystając ze wszystkich powyższych komentarzy, skompilowałem następujący kod, który działa na moje potrzeby:

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

Przetestowałem to na iPadzie, Androidzie (przeglądarka i Chrome), Blackberry Playbook, iPhone 4s, Windows Phone 8, IE 10, IE 8, IE 10 (Windows 8 z ekranem dotykowym), Opera, Chrome i Firefox.

Obecnie nie działa w systemie Windows Phone 7 i nie byłem jeszcze w stanie znaleźć rozwiązania dla tej przeglądarki.

Mam nadzieję, że ktoś uzna to za przydatne.

David
źródło
Czy jest jakiś powód, dla którego nie można użyć: function is_touch_device () {return !! ('ontouchstart' w oknie) || !! („msmaxtouchpoints” w nawigatorze); };
sidonaldson
użycie tej funkcji będzie działać, ale ogólnie lubię używać powyższej metody zmiennej, więc jest ona testowana tylko raz i jest szybsza, gdy sprawdzę później w kodzie. Odkryłem również, że muszę przetestować, czy msMaxTouchPoints ma więcej niż 0, ponieważ IE 10 w systemie Windows 8 bez ekranu dotykowego zwraca 0 jako msMaxTouchPoints.
David
wraca truena moim Firefoksie 32 na Windows 7 :(
vsync
Zarówno Firefox 33, jak i 33.1 w systemie Windows 8 pokazują poprawnie fałsz w moim systemie. Jeśli uaktualnisz Firefoksa do najnowszej wersji, czy nadal będzie on prawdziwy? Czy na twoim komputerze może być zainstalowane urządzenie, które może powodować, że Firefox niepoprawnie myśli, że Twój komputer ma dotyk?
David
>>> 'ontouchstart' w oknie >>> true FF 51.0.1 na ubuntu
Ravi Gadhia
25

Od czasu wprowadzenia funkcji mediów interaktywnych możesz po prostu:

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

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

Aktualizacja (z uwagi na komentarze): powyższym rozwiązaniem jest wykrycie, czy „zgrubny wskaźnik” - zwykle ekran dotykowy - jest głównym urządzeniem wejściowym. Jeśli chcesz sprawdzić, czy urządzenie, na przykład mysz, ma również ekran dotykowy, możesz any-pointer: coarsezamiast tego użyć .

Aby uzyskać więcej informacji, spójrz tutaj: Wykrywanie, że przeglądarka nie ma myszy i jest tylko dotykowa

Blackbam
źródło
3
To zdecydowanie najlepsze rozwiązanie, dziękuję! Chociaż zalecałbym używanie, (pointer: coarse)ponieważ najprawdopodobniej jesteś ukierunkowany tylko na główny wkład. Może być stosowany w produkcji, ponieważ kilka nieobsługiwanych przeglądarek jest przeznaczonych wyłącznie na komputery. Jest świetny artykuł na ten temat na temat sztuczek css .
Fabian von Ellerts
2
To jedyne przetestowane przeze mnie rozwiązanie, które działa w każdej sytuacji. Dzięki!
kaiserkiwi
20

Podoba mi się ten:

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

alert(isTouchDevice());
Benny Neugebauer
źródło
12
Nie ma potrzeby używania wyrażenia potrójnego, aby zwrócić wartość logiczną. Wystarczy użyć wyrażenia, aby zwrócić wartość logiczną. function isTouchDevice(){ return (window.ontouchstart !== undefined); }
Tim Vermaelen,
1
Możesz także użyć: var isTouch = 'ontouchstart' in window;jednak nie działa to z najnowszym Chrome (v31), var isTouch = 'createTouch' in window.document;nadal działa.
Olivier
2
Jak już wspomniano w komentarzach do wcześniej zaakceptowanego pytania. „Modernizr nie testuje ekranów dotykowych. Testuje na obecność zdarzeń dotykowych w przeglądarce”. Twoja funkcja jest technicznie hasTouchEvents () nie isTouchDevice ()
hexalys
Pamiętaj, że testy tylko podobnych metod touchstartnie rozpoznają urządzenia Surface jako urządzenia dotykowego, ponieważ IE używa pointerzdarzeń.
CookieMonster,
1
Może @Nis miał rację, ale w Firefox 39 poprawnie zwraca false.
Dan Dascalescu,
17

Jeśli korzystasz z Modernizr , jest bardzo łatwy w użyciu, Modernizr.touchjak wspomniano wcześniej.

Jednak wolę używać kombinacji Modernizr.touchtestów użytkownika i użytkownika, dla bezpieczeństwa.

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
    }

Jeśli nie korzystasz z Modernizr, możesz po prostu zastąpić Modernizr.touchpowyższą funkcję('ontouchstart' in document.documentElement)

Należy również pamiętać, że testowanie agenta użytkownika iemobilezapewni szerszy zakres wykrytych urządzeń mobilnych Microsoft niżWindows Phone .

Zobacz także to SO pytanie

Piotruś Pan
źródło
8
Wiele punktów bonusowych za „zrób coś drażliwego” i „nie mogę tego dotknąć”
Lee Saxon
sprawdzasz wiele razy dla tych samych urządzeń i robisz wiele Regeksów, kiedy możesz użyć tylko jednego. ponadto wykonujesz wyrażenia regularne bez rozróżniania wielkości liter, ale ciąg znaków jest już pisany małymi literami.
caesarsol,
1
to powinno wystarczyć:/(iphone|ipod|ipad|android|iemobile|blackberry|bada)/.test(window.navigator.userAgent.toLowerCase())
caesarsol,
Czy jest jakiś powód, aby małe litery lub dopasować wielkość liter bez rozróżniania wielkości liter? Kiedy „iOS”, „Android” lub „IEMobile” używa innej obudowy?
Henrik N
14

Wypróbowaliśmy implementację modernizatora, ale wykrywanie zdarzeń dotykowych nie jest już spójne (IE 10 ma zdarzenia dotykowe na pulpicie systemu Windows, IE 11 działa, ponieważ porzucono zdarzenia dotykowe i dodano interfejs API wskaźnika).

Postanowiliśmy więc zoptymalizować witrynę jako witrynę dotykową, o ile nie wiemy, jaki typ danych wejściowych ma użytkownik. Jest to bardziej niezawodne niż jakiekolwiek inne rozwiązanie.

Nasze badania mówią, że większość użytkowników komputerów przesuwa kursor myszy nad ekranem przed kliknięciem, dzięki czemu możemy je wykryć i zmienić zachowanie, zanim będą mogli kliknąć lub najechać kursorem.

To jest uproszczona wersja naszego kodu:

var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
    isTouch = false;
    window.removeEventListener('mousemove', mouseMoveDetector);
});
Martin Lantzsch
źródło
dzisiejsze komputery mają zarówno dotyk, jak i mysz ... musisz to odróżnić. absolutnie trzeba wiedzieć, czy to tylko dotyk, mysz, czy jedno i drugie. 3 różne stany.
vsync
1
Tak, masz rację, ale to bardzo trudne. W najlepszym przypadku twoja aplikacja jest zaprojektowana do użycia przez dowolny kontroler wejściowy i nie ma znaczenia, czy użytkownik ma ekran dotykowy, mysz, klawiaturę czy wszystko razem.
Martin Lantzsch
1
Zachowanie użytkownika jest ważniejsze niż rzeczywista informacja o tym, jakie urządzenie ma użytkownik. Kiedy wiesz, że użytkownik ma mysz, ekran dotykowy i klawiaturę - co wtedy? Obsługuj zachowanie (ruch myszy, dotyk, ruch klawiszy itp.). Użytkownicy mogą zmieniać typ danych wejściowych w „środowisku wykonawczym”, jest to naprawdę paskudny problem, gdy tworzysz prawdziwą aplikację, która jest używana od 8 do 5 bez ponownego ładowania.
Martin Lantzsch
2
+1 Pragmatycznie jest to dla mnie najlepsza odpowiedź. Na przykład mam siatki danych. Te siatki danych pokażą „ikonę edycji”, którą należy dotknąć w celu edycji, lub menu kontekstowe, aby uzyskać więcej opcji. Jeśli zostanie wykryty ruch myszy, usuwam ikonę (oszczędza miejsce na siatce), a użytkownicy mogą kliknąć dwukrotnie lub kliknąć prawym przyciskiem myszy.
prograhammer,
3
chrome na urządzeniach dotykowych czasami uruchamia
ruch
9

Working Fiddle

Osiągnąłem to w ten sposób;

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
źródło
nie wykrywa tabletu z systemem Windows
Dan Beaulieu
@DanBeaulieu, czy możesz być specyficzny dla urządzenia, ponieważ mam telefon z systemem Windows, dla którego działa dobrze, użyłem go również w mojej aplikacji, która jest QA: ED, ponownie go sprawdzę i zaktualizuję odpowiedź. Przepraszamy za niedogodności
Aamir Shahzad
Nie jestem pewien, który rok, to pro powierzchni Windows, który należy do współpracownika. Po dodaniu modernizatora uruchomiliśmy go.
Dan Beaulieu
To poprawnie zgłoszono Non-Touch na moim komputerze z systemem Windows 7 i dotknij na laptopie z systemem Windows 8 z ekranem dotykowym i telefonie z systemem Android 4.4 MotoX.
Clay Nichols
Daje fałszywie pozytywny wynik w Chrome (46) na moim komputerze Mac
Patrick Fabrizius
9

Jest coś lepszego niż sprawdzenie, czy mają ekran dotykowy, to sprawdzenie, czy go używają, a ponadto łatwiej to sprawdzić.

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

Ten działa dobrze nawet w tabletach z systemem 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
źródło
4

Użyłem fragmentów powyższego kodu do wykrycia, czy dotyk, więc moje fantazyjne ramki iframe pojawiały się na komputerach stacjonarnych, a nie dotykowe. Zauważyłem, że Opera Mini dla Androida 4.0 wciąż rejestruje się jako urządzenie bezdotykowe, gdy używa samego kodu blmstr. (Czy ktoś wie dlaczego?)

Skończyło się na tym, że:

<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>
Kochany
źródło
czy mógłbyś wyjaśnić, dlaczego nie używać pojedynczego połączenia z pojedynczym wyrażeniem regularnym /iPhone|iPod|iPad|Android|BlackBerry/?
user907860
Opera Mini wykonuje renderowanie na serwerach Opery, a nie na samym urządzeniu, więc jest to trochę dziwne.
bluesmoon
4

Największa „gotcha” z próbą wykrycia dotyku dotyczy urządzeń hybrydowych, które obsługują zarówno dotyk, jak i gładzik / mysz. Nawet jeśli jesteś w stanie poprawnie wykryć, czy urządzenie użytkownika obsługuje dotyk, tak naprawdę musisz zrobić to, z którego urządzenia wejściowego korzysta aktualnie użytkownik . Tutaj jest szczegółowy opis tego wyzwania i możliwe rozwiązanie .

Zasadniczo podejście do dowiedzieć się, czy dany użytkownik po prostu dotknął ekranu lub używana jest mysz / trackpad zamiast to zarejestrować się zarówno touchstarti mouseoverimprezy na stronie:

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

Akcja dotykowa wyzwoli oba te zdarzenia, chociaż pierwsza ( touchstart) zawsze jest pierwsza na większości urządzeń. Licząc na przewidywalną sekwencję zdarzeń, możesz stworzyć mechanizm, który dynamicznie dodaje lub usuwa can-touchklasę do katalogu głównego dokumentu, aby odzwierciedlić aktualny typ danych wejściowych użytkownika w tym momencie w dokumencie:

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

Więcej informacji tutaj .

ptysie kokosowe
źródło
3

Sprawdź ten post , daje naprawdę fajny fragment kodu dotyczący tego, co zrobić, gdy wykryte zostaną urządzenia dotykowe lub co zrobić, gdy wywoływane jest zdarzenie touchstart:

$(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
źródło
3

Unikałbym używania szerokości ekranu w celu ustalenia, czy urządzenie jest urządzeniem dotykowym. Istnieją ekrany dotykowe znacznie większe niż 699px, pomyśl o Windows 8. Navigatior.userAgent może być przyjemny, aby zastąpić fałszywe postawy.

Polecam sprawdzenie tego problemu w Modernizr.

Czy chcesz sprawdzić, czy urządzenie obsługuje zdarzenia dotykowe, czy jest urządzeniem dotykowym. Niestety to nie to samo.

hybrydowy
źródło
3

Nie, to niemożliwe. Doskonałe odpowiedzi są zawsze tylko częściowe, ponieważ każda metoda da fałszywe pozytywne i fałszywe negatywne. Nawet przeglądarka nie zawsze wie, czy ekran dotykowy jest obecny, ze względu na interfejsy API systemu operacyjnego, a fakt może się zmienić podczas sesji przeglądarki, szczególnie w przypadku konfiguracji typu KVM.

Zobacz dalsze szczegóły w tym doskonałym artykule:

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

Artykuł sugeruje, aby ponownie rozważyć założenia, które sprawiają, że chcesz wykryć ekrany dotykowe, prawdopodobnie są one błędne. (Sprawdziłem własną aplikację i moje założenia rzeczywiście były błędne!)

Artykuł podsumowuje:

W przypadku układów załóż, że wszyscy mają ekran dotykowy. Użytkownicy myszy mogą korzystać z dużych kontrolek interfejsu użytkownika znacznie łatwiej niż użytkownicy dotykowi - z małych. To samo dotyczy stanów najechania kursorem.

W przypadku zdarzeń i interakcji załóż, że każdy może mieć ekran dotykowy. Wdrażaj interakcje klawiatury, myszy i dotyku obok siebie, upewniając się, że nikt się nie blokuje.

Dave Burt
źródło
3

Wiele z nich działa, ale albo wymagają jQuery, albo linters javascript narzekają na składnię. Biorąc pod uwagę, że twoje początkowe pytanie wymaga „JavaScript” (nie jQuery, nie Modernizr) sposobu rozwiązania tego problemu, oto prosta funkcja, która działa za każdym razem. Jest to również tak minimalne, jak to tylko możliwe.

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

console.log(isTouchDevice());

Ostatnią zaletą, o której wspomnę, jest to, że ten kod jest niezależny od frameworka i urządzenia. Cieszyć się!

seanforyou23
źródło
function isTouchScreen() { return window.matchMedia('(hover: none)').matches;}To zadziałało dla mnie, dlatego dodam coś do tej odpowiedzi, ponieważ spodziewałem się także waniliowego wątku JS, gdy Google mnie tu sprowadził.
Daniel Lavedonio de Lima
2

Wygląda na to, że Chrome 24 obsługuje teraz zdarzenia dotykowe, prawdopodobnie w systemie Windows 8. Więc zamieszczony tutaj kod już nie działa. Zamiast próbować wykryć, czy przeglądarka obsługuje dotyk, teraz wiążę zdarzenia dotyku i kliknięcia i upewniam się, że wywoływane jest tylko jedno:

myCustomBind = function(controlName, callback) {

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

    callback.call();
  });
};

A potem nazywając to:

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

Mam nadzieję że to pomoże !

wizmagister
źródło
1
Powiązany wątek, stackoverflow.com/questions/12566306/…
Air
2

Wszystkie obsługiwane przeglądarki oprócz Firefoksa dla komputerów stacjonarnych są zawsze PRAWDZIWE, ponieważ Firefox dla komputerów stacjonarnych obsługuje responsywne projektowanie dla programistów, nawet jeśli klikniesz przycisk dotykowy lub nie!

Mam nadzieję, że Mozilla naprawi to w następnej wersji.

Korzystam z przeglądarki Firefox 28.

function isTouch()
{
    return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}
xicooc
źródło
to wciąż wersja 32.0 i jeszcze tego nie naprawili! szalony. dlaczego to nie może być przełączane? To zawsze zwraca true:(
vsync
2

jQuery v1.11.3

W udzielonych odpowiedziach jest wiele dobrych informacji. Ale ostatnio spędziłem dużo czasu próbując związać wszystko razem w działające rozwiązanie dla osiągnięcia dwóch rzeczy:

  1. Wykryj, że używane urządzenie jest urządzeniem z ekranem dotykowym.
  2. Wykryj, że urządzenie zostało dotknięte.

Poza tym postem i wykrywaniem urządzeń dotykowych z JavaScriptem , ten post przez Patricka Lauke był niezwykle pomocny: https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how /

Oto kod ...

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

Ważny! The*.on( events [, selector ] [, data ], handler ) potrzeb Sposób mieć przełącznik, zazwyczaj element, który można obsługiwać z „touchstart” zdarzenie lub inne podobne zdarzenia związanego z elementami. W tym przypadku jest to element hiperłącza „a”.

Teraz nie musisz obsługiwać zwykłego klikania myszą w JavaScript, ponieważ możesz użyć CSS do obsługi tych zdarzeń za pomocą selektorów dla elementu „a” hiperłącza, takiego jak:

/* unvisited link */
a:link 
{

}

/* visited link */
a:visited 
{

}

/* mouse over link */
a:hover 
{

}

/* selected link */
a:active 
{

}

Uwaga: Istnieją również inne selektory ...

serge-k
źródło
1
var isTouchScreen = 'createTouch' in document;

lub

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

byłby to dokładniejszy test, jak sądzę.

samuel segal
źródło
3
Warto zauważyć, że uaodnosi się do navigator.userAgent. Wykrywanie na podstawie szerokości ekranu może również dać fałszywy wynik, jeśli ktoś otworzy przeglądarkę w trybie innym niż pełnoekranowy.
HoLyVieR
1

Używam:

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

w jQuery mobile 1.0.1

znak
źródło
1

Miałem też wiele problemów z różnymi opcjami wykrywania w JavaScript, czy strona jest wyświetlana na urządzeniu z ekranem dotykowym, czy nie. IMO, jak na razie, nie istnieje żadna prawdziwa opcja do prawidłowego wykrycia opcji. Przeglądarki albo zgłaszają zdarzenia dotykowe na komputerach stacjonarnych (ponieważ system operacyjny może być gotowy na dotyk), albo niektóre rozwiązania nie działają na wszystkich urządzeniach mobilnych.

W końcu zdałem sobie sprawę, że od samego początku podążałem za niewłaściwym podejściem: jeśli moja strona miałaby wyglądać podobnie na urządzeniach dotykowych i bezdotykowych, być może nie powinienem w ogóle martwić się wykryciem właściwości: Mój scenariusz był aby dezaktywować podpowiedzi nad przyciskami na urządzeniach dotykowych, ponieważ prowadzą one do podwójnego stuknięcia, w którym chciałem jednego stuknięcia, aby aktywować przycisk.

Moim rozwiązaniem było przefakturowanie widoku, tak aby nie było potrzeby wyświetlania podpowiedzi nad przyciskiem, a ostatecznie nie musiałem wykrywać urządzenia dotykowego w Javascript za pomocą metod, które mają swoje wady .

Michał
źródło
1

Możesz zainstalować modernizator i użyć prostego zdarzenia dotykowego. Jest to bardzo skuteczne i działa na każdym urządzeniu, które przetestowałem, w tym na powierzchni okien!

Stworzyłem 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
źródło
3
Witamy w SO! Kod sam w sobie (podobnie jak kod nieskomentowany) rzadko stanowi odpowiedź. Możesz poprawić tę odpowiedź, dodając wyjaśnienie fragmentu.
ebarr
1

Wydaje się, że praktyczna odpowiedź dotyczy kontekstu:

1) Witryna publiczna (bez logowania)
Kod interfejsu użytkownika do pracy z obiema opcjami jednocześnie.

2) Witryna logowania
Sprawdź, czy w formularzu logowania nastąpił ruch myszy, i zapisz to w ukrytym wejściu. Wartość jest przekazywana z poświadczeniami logowania i dodawana do sesji użytkownika , dzięki czemu można jej używać na czas trwania sesji.

Jquery, aby dodać tylko do strony logowania:

$('#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 do @Dave Burt i +1 do @Martin Lantzsch w odpowiedziach)

prograhammer
źródło
1

Problem

Ze względu na urządzenia hybrydowe, które wykorzystują kombinację wprowadzania dotykowego i myszy, musisz być w stanie dynamicznie zmieniać stan / zmienną, która kontroluje, czy fragment kodu powinien być uruchamiany, jeśli użytkownik jest użytkownikiem dotykowym, czy nie.

Urządzenia dotykowe również uruchamiają się mousemovepo dotknięciu.

Rozwiązanie

  1. Załóżmy, że dotyk jest fałszywy przy ładowaniu.
  2. Poczekaj, aż touchstartzdarzenie zostanie uruchomione, a następnie ustaw wartość true.
  3. Jeśli uruchomiono funkcję touchstart, dodaj procedurę obsługi myszy.
  4. Jeśli czas między uruchomieniem dwóch zdarzeń przesunięcia myszy był krótszy niż 20 ms, załóż, że używają myszy jako danych wejściowych. Usuń zdarzenie, ponieważ nie jest już potrzebne, a ruch myszy jest kosztownym wydarzeniem dla urządzeń myszy.
  5. Gdy tylko touchstart zostanie ponownie uruchomiony (użytkownik wrócił do korzystania z dotyku), zmienna zostaje ponownie ustawiona na true. Powtórz proces, aby ustalić go w sposób dynamiczny. Jeśli jakimś cudem ruch myszy zostanie dwukrotnie wystrzelony po dotknięciu absurdalnie szybko (w moich testach jest to praktycznie niemożliwe w ciągu 20 ms), następny start dotykowy przywróci mu wartość prawdy.

Testowane na Safari iOS i Chrome na Androida.

Uwaga: brak 100% pewności co do zdarzeń wskaźnika dla MS Surface itp.

Demo Codepen


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);
}
mroźny
źródło
1

Właściwie to zbadałem to pytanie i rozważyłem wszystkie sytuacje. ponieważ jest to również duży problem w moim projekcie. Więc osiągam poniższą funkcję, działa dla wszystkich wersji wszystkich przeglądarek na wszystkich urządzeniach:

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

Wskazówka : Zdecydowanie poisTouchDeviceprostu zwracabooleanwartości.

AmerllicA
źródło
0

Rozszerzony supportobiekt jQuery :

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

A teraz możesz to sprawdzić w dowolnym miejscu, na przykład:

if( jQuery.support.touch )
   // do touch stuff
vsync
źródło
0

Wydaje mi się, że do tej pory działało to dobrze:

//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
źródło
0

Gdy mysz jest podłączona, można założyć z dość wysokim przepływem danych (powiedziałbym praktycznie 100%), że użytkownik porusza myszką co najmniej niewielką odległość po przygotowaniu strony - bez żadnego kliknięcia. Mechanizm poniżej to wykrywa. Jeśli zostanie wykryty, uważam to za oznakę braku obsługi dotyku lub, jeśli jest obsługiwana, ma niewielkie znaczenie, gdy używana jest mysz. Zakłada się, że urządzenie dotykowe zostanie wykryte.

EDYTOWAĆ To podejście może nie pasować do wszystkich celów. Można go użyć do sterowania funkcjami aktywowanymi na podstawie interakcji użytkownika na ładowanej stronie, na przykład przeglądarki zdjęć. Poniższy kod pozostawi również zdarzenie mousemove związane na urządzeniach bez myszy, ponieważ wyróżnia się teraz. Inne podejścia mogą być lepsze.

Z grubsza wygląda to tak (przepraszam za jQuery, ale podobnie w czystym JavaScript):

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
źródło