Erkennen, dass der Browser keine Maus hat und nur mit Berührung erreichbar ist

149

Ich entwickle eine Webanwendung (keine Website mit Seiten mit interessantem Text) mit einer ganz anderen Oberfläche für Berührungen (Ihr Finger verbirgt den Bildschirm, wenn Sie klicken) und Maus (hängt stark von der Schwebevorschau ab). Wie kann ich feststellen, dass mein Benutzer keine Maus hat, um ihm die richtige Benutzeroberfläche zu präsentieren? Ich habe vor, einen Schalter für Leute mit Maus und Berührung zu hinterlassen (wie einige Notebooks).

Die Berührungsereignisfunktion im Browser bedeutet nicht, dass der Benutzer ein Berührungsgerät verwendet (z. B. schneidet Modernizr es nicht ab). Der Code, der die Frage richtig beantwortet, sollte false zurückgeben, wenn das Gerät eine Maus hat, andernfalls true. Bei Geräten mit Maus und Berührung sollte false zurückgegeben werden (nicht nur Berühren).

Nebenbei bemerkt, meine Touch-Oberfläche eignet sich möglicherweise auch nur für Tastaturgeräte. Es ist also eher der Mangel an Maus, den ich erkennen möchte.

Um die Notwendigkeit klarer zu machen, ist hier die API, die ich implementieren möchte:

// 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);
nraynaud
quelle
Ich denke, Sie müssen Ihr Design überdenken, wenn Sie möchten, dass eine App sowohl auf Desktop- als auch auf Mobile / Touch-Anwendungen anwendbar ist, aber jeweils unterschiedliche Verhaltensweisen aufweist. Ich denke nicht, dass das, wonach Sie suchen, derzeit tatsächlich möglich ist, da eine schnelle Suche bei Google nach "Javascript Detect Mouse" einen mäßig nützlichen Beitrag auf quirksmode.org zum Erkennen verschiedener Zustände der Maus (Klicks, Position, etc), aber NULL ergibt, ob die Maus tatsächlich existiert oder nicht.
davethegr8
24
Vielleicht liegt das daran, dass Google nicht geholfen hat, dass ich es hier gefragt habe.
Nraynaud
2
Haben Sie Document Mouseenter von jquery ausprobiert? $ (document) .mouseenter (function (e) {alert ("mouse");});
Parag Gajjar
4
Nachdem ich fast ein Dutzend vielversprechende Wege in Betracht gezogen habe, um jeden innerhalb von Minuten abzulehnen, treibt mich diese Frage ganz großartig an.
Jordan Gray

Antworten:

65

Das Hauptproblem besteht darin, dass Sie die folgenden verschiedenen Klassen von Geräten / Anwendungsfällen haben:

  1. Maus und Tastatur (Desktop)
  2. Nur berühren (Telefon / Tablet)
  3. Maus, Tastatur und Touch (Touch-Laptops)
  4. Touch und Tastatur (Bluetooth-Tastatur auf dem Tablet)
  5. Nur Maus (Benutzer / Browser deaktiviert)
  6. Nur Tastatur (Benutzer / Browser-Einstellung deaktiviert)
  7. Berühren und Maus (dh Hover-Ereignisse vom Galaxy Note 2-Stift)

Was noch schlimmer ist, ist, dass man von einigen dieser Klassen zu anderen wechseln kann (Stecker in eine Maus, stellt eine Verbindung zur Tastatur her), oder ein Benutzer scheint sich auf einem normalen Laptop zu befinden, bis er den Bildschirm berührt.

Sie gehen zu Recht davon aus, dass das Vorhandensein von Ereigniskonstruktoren im Browser kein guter Weg ist, um vorwärts zu kommen (und etwas inkonsistent ist). Darüber hinaus ist die Verwendung von Ereignissen selbst kein vollständiger Beweis, es sei denn, Sie verfolgen ein bestimmtes Ereignis oder versuchen nur, einige der oben genannten Klassen auszuschließen.

Angenommen, Sie haben festgestellt, dass ein Benutzer eine echte Mausbewegung ausgegeben hat (nicht die falsche aus Berührungsereignissen, siehe http://www.html5rocks.com/en/mobile/touchandmouse/ ).

Dann was?

Sie aktivieren Schwebestile? Sie fügen weitere Schaltflächen hinzu?

In beiden Fällen erhöhen Sie die Zeit bis zum Glas, da Sie auf das Auslösen eines Ereignisses warten müssen.

Aber was passiert dann, wenn Ihr edler Benutzer entscheidet, dass er seine Maus ausstecken und die volle Berührung ausführen möchte? Warten Sie, bis er Ihre jetzt überfüllte Benutzeroberfläche berührt, und ändern Sie sie dann, nachdem er sich bemüht hat, Ihre jetzt überfüllte Benutzeroberfläche zu lokalisieren?

In Aufzählungszeichen unter Angabe von stucox unter https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101

  • Wir wollen das Vorhandensein einer Maus erkennen
  • Ae kann wahrscheinlich nicht erkennen, bevor ein Ereignis ausgelöst wird
  • Als solches stellen wir fest, dass in dieser Sitzung eine Maus verwendet wurde - dies erfolgt nicht sofort nach dem Laden der Seite
  • Wir können wahrscheinlich auch nicht erkennen, dass es keine Maus gibt - sie wäre undefiniert, bis sie wahr ist (ich denke, dies ist sinnvoller, als sie falsch zu setzen, bis sie bewiesen ist).
  • Und wir können wahrscheinlich nicht erkennen, ob eine Maus während der Sitzung getrennt ist - das ist nicht zu unterscheiden, wenn der Benutzer nur mit der Maus aufgibt

Nebenbei bemerkt: Der Browser weiß, wann ein Benutzer eine Maus einsteckt / eine Verbindung zu einer Tastatur herstellt, setzt sie jedoch nicht JavaScript aus.

Dies sollte Sie zu Folgendem führen:

Das Verfolgen der aktuellen Fähigkeiten eines bestimmten Benutzers ist komplex, unzuverlässig und von zweifelhaftem Wert

Die Idee der progressiven Verbesserung trifft hier jedoch recht gut zu. Erstellen Sie eine Erfahrung, die unabhängig vom Kontext des Benutzers reibungslos funktioniert. Nehmen Sie dann Annahmen basierend auf Browserfunktionen / Medienabfragen vor, um Funktionen hinzuzufügen, die im angenommenen Kontext relativ sind. Das Vorhandensein einer Maus ist nur eine von vielen Möglichkeiten, wie verschiedene Benutzer auf verschiedenen Geräten Ihre Website erleben. Erstellen Sie etwas mit Verdienst im Kernel und sorgen Sie sich nicht zu sehr darum, wie Leute auf die Schaltflächen klicken.

Wyatt
quelle
3
gute Antwort. Hoffentlich hat der Benutzer immer einen Bildschirm! Ich denke, es ist sinnvoll, eine Schnittstelle zu erstellen, die dem aktuellen Interaktionsmodus des Benutzers entspricht. Auf einem Touch-Laptop ist es sinnvoll, die App (dh die :hoverElemente und ähnliche Dinge) anzupassen , wenn der Benutzer von der Maus zur Berührung wechselt. Es ist unwahrscheinlich, dass der Benutzer derzeit genau zur gleichen Zeit Maus + Berührung verwendet (ich meine, es ist, als wären 2 Mäuse an denselben Computer angeschlossen, hahaha)
Sebastien Lorber
@SebastienLorber - hasse es, es dir zu brechen, aber Benutzer haben nicht unbedingt immer einen Bildschirm. ( Ist es möglich, Javascript zu verwenden, um festzustellen, ob ein Bildschirmleser auf einem Computer des Benutzers ausgeführt wird? )
ashleedawg
57

Wie wäre es, wenn Sie auf ein Mausbewegungsereignis im Dokument warten. Bis Sie dieses Ereignis hören, nehmen Sie an, dass das Gerät nur eine Berührung oder eine Tastatur ist.

var mouseDetected = false;
function onMouseMove(e) {
  unlisten('mousemove', onMouseMove, false);
  mouseDetected = true;
  // initializeMouseBehavior();
}
listen('mousemove', onMouseMove, false);

(Wo listenund unlistendelegieren an addEventListeneroder attachEventnach Bedarf.)

Hoffentlich würde dies nicht zu viel visuellem Ruck führen, es wäre scheiße, wenn Sie massive Neugestaltungen basierend auf dem Modus benötigen ...

Dan
quelle
2
Es ist eine gute Idee, aber leider macht die Verzögerung der Antwort es unbrauchbar, wenn die Benutzeroberfläche der Anwendung davon abhängt, ob eine Maus verfügbar ist. Dies gilt insbesondere dann, wenn die Anwendung möglicherweise iframed ist, sodass Mausereignisse sie nur treffen, wenn die Maus bewegt sich über den Iframe selbst ..
Jon Gjengset
7
Dies könnte funktionieren, wenn die Anwendung mit einem Begrüßungsbildschirm und einer Schaltfläche "Weiter" startet. Wenn sich die Maus vor dem ersten Mousedown-Ereignis bewegt, haben Sie eine Maus. Es würde nur fehlschlagen, wenn die Taste direkt unter der Maus geladen wird und der Benutzer eine sehr ruhige Hand hat (selbst das Bewegen von 1 Pixel sollte aufgenommen werden).
SpliFF
49
nette Idee, scheint aber in unseren Tests nicht zu funktionieren . iPads lösen dieses Ereignis aus.
Jeff Atwood
3
@ JeffAtwood, was hast du in deinem Fall gemacht?
Michael Haren
2
iPads lösen definitiv das Mousemove-Ereignis unmittelbar vor dem Mousedown-Ereignis aus. Ich habe festgestellt, dass Mousedown Count> 0 und Mousedown Count == Mousemove Count eine gute Möglichkeit sind, keine Maus zu erkennen. Ich kann das nicht mit einer echten Maus duplizieren.
Peter Wooster
36

Ab 2018 gibt es eine gute und zuverlässige Methode, um festzustellen, ob ein Browser über eine Maus (oder ein ähnliches Eingabegerät) verfügt: CSS4-Medieninteraktionsfunktionen, die jetzt von fast jedem modernen Browser (außer IE 11 und speziellen mobilen Browsern) unterstützt werden.

W3C:

Die Zeigermedienfunktion wird verwendet, um das Vorhandensein und die Genauigkeit eines Zeigegeräts wie einer Maus abzufragen.

Siehe die folgenden Optionen:

    /* The primary input mechanism of the device includes a 
pointing device of limited accuracy. */
    @media (pointer: coarse) { ... }

    /* The primary input mechanism of the device 
includes an accurate pointing device. */
    @media (pointer: fine) { ... }

    /* The primary input mechanism of the 
device does not include a pointing device. */
    @media (pointer: none) { ... }

    /* Primary input mechanism system can 
       hover over elements with ease */
    @media (hover: hover) { ... }

    /* Primary input mechanism cannot hover 
       at all or cannot conveniently hover 
       (e.g., many mobile devices emulate hovering
       when the user performs an inconvenient long tap), 
       or there is no primary pointing input mechanism */
    @media (hover: none) { ... }

    /* One or more available input mechanism(s) 
       can hover over elements with ease */
    @media (any-hover: hover) { ... }


    /* One or more available input mechanism(s) cannot 
       hover (or there are no pointing input mechanisms) */
    @media (any-hover: none) { ... }

Medienabfragen können auch in JS verwendet werden:

if(window.matchMedia("(any-hover: none)").matches) {
    // do sth
}

Verbunden:

W3-Dokumentation: https://www.w3.org/TR/mediaqueries-4/#mf-interaction

Browserunterstützung: https://caniuse.com/#search=media%20features

Ähnliches Problem: Ermitteln Sie, ob ein Clientgerät die Zustände: hover und: focus unterstützt

Blackbam
quelle
Ich persönlich mag diese Antwort, aber ab sofort (19.10.) Sind @ cania Hover- und Pointer-CSS-Abfragen laut caniuse.com nur auf ~ 85% der Geräte weltweit verfügbar. Sicher nicht schlecht, 95% oder mehr sind vorzuziehen. Hoffentlich wird dies bald zum Standard auf Geräten.
MQuiggGeorgia
1
@MQuiggGeorgia Grundsätzlich stimme ich Ihrer Kritik grundsätzlich zu, sie wird noch nicht überall unterstützt. Trotzdem sagt caniuse.com für mich, dass es zu 91,2% unterstützt wird ( caniuse.com/#feat=css-media-interaction ). Bei näherer Betrachtung wird es überall unterstützt, außer in IE 11 und speziellen abgeflachten Browsern auf Mobilgeräten. Um fair zu sein, gilt dies für alle modernen Funktionen, da Microsoft die Implementierung von IE-Funktionen vor langer Zeit eingestellt hat. Für IE 11 können Sie hier einen Fallback aus den anderen Antworten verwenden.
Blackbam
23

Die Antwort von @ Wyatt ist großartig und gibt uns viel zu denken.

In meinem Fall habe ich mich entschieden, auf die erste Interaktion zu warten, um erst dann ein Verhalten festzulegen. Selbst wenn der Benutzer eine Maus hat, werde ich als Berührungsgerät behandelt, wenn die erste Interaktion eine Berührung war.

In Anbetracht der angegebenen Reihenfolge, in der Ereignisse verarbeitet werden :

  1. Touchstart
  2. touchmove
  3. Touchend
  4. Mouseover
  5. Mausbewegung
  6. Maus nach unten
  7. mouseup
  8. klicken

Wir können davon ausgehen, dass ein Mausereignis, das vor dem Berühren ausgelöst wird, ein echtes Mausereignis ist, kein emuliertes. Beispiel (mit jQuery):

$(document).ready(function() {
    var $body = $('body');
    var detectMouse = function(e){
        if (e.type === 'mousedown') {
            alert('Mouse interaction!');
        }
        else if (e.type === 'touchstart') {
            alert('Touch interaction!');
        }
        // remove event bindings, so it only runs once
        $body.off('mousedown touchstart', detectMouse);
    }
    // attach both events to body
    $body.on('mousedown touchstart', detectMouse);
});

Das hat bei mir funktioniert

Hugo Silva
quelle
Funktioniert nicht für mich, Ipad Safari (IOS8.3) erkennt auch eine Maus mit diesem Snippet
Netzaffin
3
@netzaffin. Vielen Dank für das Feedback. Ich fand es konsistenter, wenn Sie Mousedown anstelle von Mouseover verwenden. Würden Sie sich diese Geige von Ihrem IOS ansehen und mir das Ergebnis mitteilen? Prost jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva
1
Wenn Sie einen Touchscreen mit einer Maus haben, wird nur die zuerst verwendete Eingabemethode erkannt.
0xcaff
11

Es ist nur möglich zu erkennen, ob ein Browser berührungsfähig ist . Es ist nicht möglich festzustellen, ob tatsächlich ein Touchscreen oder eine Maus angeschlossen ist.

Man kann die Verwendung jedoch priorisieren, indem man das Berührungsereignis anstelle des Mausereignisses abhört, wenn die Berührungsfähigkeit erkannt wird.

So erkennen Sie browserübergreifende Berührungsfunktionen:

function hasTouch() {
    return (('ontouchstart' in window) ||       // html5 browsers
            (navigator.maxTouchPoints > 0) ||   // future IE
            (navigator.msMaxTouchPoints > 0));  // current IE10
}

Dann kann man damit überprüfen:

if (!hasTouch()) alert('Sorry, need touch!);

oder wählen Sie, welches Ereignis Sie hören möchten:

var eventName = hasTouch() ? 'touchend' : 'click';
someElement.addEventListener(eventName , handlerFunction, false);

oder verwenden Sie separate Ansätze für Berührung oder Nichtberührung:

if (hasTouch() === true) {
    someElement.addEventListener('touchend' , touchHandler, false);

} else {
    someElement.addEventListener('click' , mouseHandler, false);

}
function touchHandler(e) {
    /// stop event somehow
    e.stopPropagation();
    e.preventDefault();
    window.event.cancelBubble = true;
    // ...
    return false; // :-)
}
function mouseHandler(e) {
    // sorry, touch only - or - do something useful and non-restrictive for user
}

Bei der Maus kann man nur erkennen, ob die Maus verwendet wird, nicht, ob sie existiert oder nicht. Man kann ein globales Flag einrichten, um anzuzeigen, dass die Maus durch Verwendung erkannt wurde (ähnlich einer vorhandenen Antwort, jedoch etwas vereinfacht):

var hasMouse = false;

window.onmousemove = function() {
    hasMouse = true;
}

(man kann nicht einschließen mouseupoder mousedownda dieses Ereignis auch durch Berühren ausgelöst werden kann)

Browser beschränken den Zugriff auf System-APIs auf niedriger Ebene, die erforderlich sind, um Funktionen wie die Hardwarefunktionen des Systems, auf dem sie verwendet werden, erkennen zu können.

Es besteht die Möglichkeit, möglicherweise ein Plugin / eine Erweiterung zu schreiben, um auf diese zuzugreifen, aber über JavaScript und DOM ist eine solche Erkennung für diesen Zweck eingeschränkt, und man müsste ein Plugin schreiben, das für die verschiedenen Betriebssystemplattformen spezifisch ist.

Fazit: Eine solche Erkennung kann nur durch eine "gute Vermutung" geschätzt werden.


quelle
8

Wenn Media Queries Level 4 in Browsern verfügbar ist, können wir die Abfragen "Zeiger" und "Hover" verwenden, um Geräte mit der Maus zu erkennen.

Wenn wir diese Informationen wirklich an Javascript weitergeben möchten, können wir eine CSS-Abfrage verwenden, um bestimmte Stile entsprechend dem Gerätetyp festzulegen, und dann getComputedStylein Javascript verwenden, um diesen Stil zu lesen und den ursprünglichen Gerätetyp daraus abzuleiten.

Eine Maus kann jedoch jederzeit angeschlossen oder vom Stromnetz getrennt werden, und der Benutzer möchte möglicherweise zwischen Berührung und Maus wechseln. Daher müssen wir diese Änderung möglicherweise erkennen und anbieten, die Benutzeroberfläche zu ändern, oder dies automatisch.

joeytwiddle
quelle
1
Insbesondere any-pointerundany-hover lassen Sie alle anwendbaren Gerätefunktionen untersuchen. Schön, einen Blick darauf zu werfen, wie wir dieses Problem in Zukunft lösen könnten! :)
Jordan Gray
2
window.matchMedia ("(beliebiger Zeiger: grob)"). entspricht === true?
4esn0k
7

Wäre es möglich, den Benutzer einfach zu bitten, auf einen Link oder eine Schaltfläche zu klicken, um die richtige Version der Anwendung einzugeben, da Sie ohnehin eine Möglichkeit zum Wechseln zwischen den Schnittstellen anbieten möchten? Dann könnten Sie sich an ihre Präferenz für zukünftige Besuche erinnern. Es ist kein Hightech, aber es ist 100% zuverlässig :-)

Brandan
quelle
2
Es ist eigentlich ein ziemlich guter Vorschlag, aber es verzögert die Zeit, bevor der Benutzer zur realen Oberfläche gelangt. Außerdem muss ich nach der ersten Auswahl eine Möglichkeit zum Wechseln bereitstellen. Am Ende ist es mehr Arbeit, als wenn es einfach erkannt werden könnte.
Jon Gjengset
1
Den Benutzer zu fragen ist eindeutig der beste Weg - wenn auch nicht immer kinderleicht - und bietet Ihnen einen bequemen Ort, um Upgrade-Benachrichtigungen zu erstellen und was nicht. Ich denke, Sie sind über das "Problem"
nachgedacht
4

@SamuelRossille Leider gibt es keine mir bekannten Browser, die die Existenz (oder das Fehlen einer) Maus aufdecken.

Wenn dies gesagt ist, müssen wir nur versuchen, mit unserer bestehenden Option ... Veranstaltungen das Beste zu geben, was wir können. Ich weiß, es ist nicht genau das, wonach Sie suchen ... stimmte zu, dass es derzeit alles andere als ideal ist.

Wir können unser Bestes tun, um herauszufinden, ob ein Benutzer zu einem bestimmten Zeitpunkt eine Maus verwendet oder berührt. Hier ist ein schnelles und schmutziges Beispiel mit jQuery & Knockout:

//namespace
window.ns = {};

// for starters, we'll briefly assume if touch exists, they are using it - default behavior
ns.usingTouch = ko.observable(Modernizr.touch); //using Modernizr here for brevity.  Substitute any touch detection method you desire

// now, let's sort out the mouse
ns.usingMouse = ko.computed(function () {
    //touch
    if (ns.usingTouch()) {
        //first, kill the base mousemove event
        //I really wish browsers would stop trying to handle this within touch events in the first place
        window.document.body.addEventListener('mousemove', function (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }, true);

        //remove mouse class from body
        $('body').removeClass("mouse");

        //switch off touch listener
        $(document).off(".ns-touch");

        // switch on a mouse listener
        $(document).on('mousemove.ns-mouse', function (e) {
            if (Math.abs(window.lastX - e.clientX) > 0 || window.lastY !== e.clientY) {
                ns.usingTouch(false);  //this will trigger re-evaluation of ns.usingMouse() and result in ns.usingMouse() === true
            }
        });

        return false;
    }
    //mouse
    else {
        //add mouse class to body for styling
        $('body').addClass("mouse");

        //switch off mouse listener
        $(document).off(".ns-mouse");

        //switch on a touch listener
        $(document).on('touchstart.ns-touch', function () { ns.usingTouch(true) });

        return true;
    }
});

//tests:
//ns.usingMouse()
//$('body').hasClass('mouse');

Sie können jetzt usingMouse () & usingTouch () binden / abonnieren und / oder Ihre Schnittstelle mit der body.mouse- Klasse formatieren . Die Benutzeroberfläche wechselt hin und her, sobald ein Mauszeiger erkannt wird und der Touchstart erfolgt.

Hoffentlich haben wir bald einige bessere Optionen von den Browser-Anbietern.

Draufgänger
quelle
2

Tera-WURFL kann Ihnen die Funktionen des Geräts, das Ihre Site besucht, mitteilen, indem die Browsersignatur mit der Datenbank verglichen wird . Schau es dir an, es ist kostenlos!

Gigi
quelle
1
Dies funktioniert nicht für Geräte mit Touchscreens und einer Maus. Zum Beispiel kann ein Windows-Desktop-Computer mit einem Touchscreen verbunden sein, hat aber normalerweise auch eine Maus, während auf einem Tablet möglicherweise auch Windows ausgeführt wird, aber möglicherweise keine Maus angeschlossen ist.
Jon Gjengset
@ Jonhoo Nehmen Sie einfach an, dass an Desktop-Betriebssystemen eine Maus angeschlossen ist. Schließlich müssen sie eine breite Palette von Software unterstützen, die nicht für Touchscreens entwickelt wurde.
Gigi
1
Was ist mit Tablets unter Windows 8? Oder Linux? Oder Laptops mit Android?
Jon Gjengset
2
@ Jonhoo Natürlich ist dieser Ansatz nicht optimal, aber es gibt (noch) keinen tragbaren Weg, dies zu wissen. Wenn Sie einen Laptop mit Android betreiben, nehmen Sie einfach an, dass er berührungsfähig ist. Wenn Sie ein Windows8-Tablet verwenden, nehmen Sie einfach an, dass es mausfähig ist (das Betriebssystem muss die Maus für Nicht-Touch-Programme emulieren).
Gigi
Dies ist jetzt so veraltet, dass es nicht mehr relevant ist.
Ingenieur
2

Warum erkennen Sie nicht einfach, ob es Berührungen erfassen und / oder auf Mausbewegungen reagieren kann?

// This will also return false on
// touch-enabled browsers like Chrome
function has_touch() {
  return !!('ontouchstart' in window);
}

function has_mouse() {
  return !!('onmousemove' in window);
}
iblue
quelle
4
Weil einige Browser (z. B. IE9) melden, dass die Funktion auch dann vorhanden ist, wenn sie niemals ausgelöst wird. Ich glaube, das ist auch das "richtige" Verhalten.
Jon Gjengset
Warum sollten Sie eine Funktion verwenden? wird einfach has_touch = 'ontouchstart' in windowausreichen und so weiter.
vsync
Nun, es funktioniert zumindest unter Chrome 47 für OS X. Kein ontouchstart melden.
Phreakhead
2

Das hat bei mir in einer ähnlichen Situation funktioniert. Nehmen Sie grundsätzlich an, dass der Benutzer keine Maus hat, bis Sie eine kurze Reihe aufeinanderfolgender Mausbewegungen sehen, ohne dazwischen Maus-Downs oder Mouseups zu machen. Nicht sehr elegant, aber es funktioniert.

var mousedown = false;
var mousemovecount = 0;
function onMouseDown(e){
    mousemovecount = 0;
    mousedown = true;
}
function onMouseUp(e){
    mousedown = false;
    mousemovecount = 0;
}
function onMouseMove(e) {
    if(!mousedown) {
        mousemovecount++;
        if(mousemovecount > 5){
            window.removeEventListener('mousemove', onMouseMove, false);
            console.log("mouse moved");
            $('body').addClass('has-mouse');
        }
    } else {
        mousemovecount = 0;
    }
}
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mousedown', onMouseDown, false);
window.addEventListener('mouseup', onMouseUp, false);
Michael Condouris
quelle
0

Werfen Sie einen Blick auf Modenizr. Eines seiner Merkmale ist Touch

http://modernizr.com/docs/#features-misc

Obwohl ich nicht vollständig getestet habe, scheint es sehr gut zu funktionieren

Auch dies ist von der modernizr Seite http://www.html5rocks.com/en/mobile/touchandmouse/ verlinkt.

Exussum
quelle
Dies versucht, die Berührungsfähigkeit zu erkennen, nicht ob es NUR Berührungsfähigkeit und keine Mausfähigkeit gibt. Diese Frage unterscheidet sich grundlegend von der Berührungserkennung.
Jimbo Jonny
0

Wie andere bereits betont haben, ist es unzuverlässig, endgültig festzustellen, ob sie eine Maus haben oder nicht. Dies kann sich je nach Gerät leicht ändern. Es ist definitiv etwas, was man mit einem booleschen Richtig oder Falsch nicht zuverlässig machen kann, zumindest auf einer Dokumentenskala.

Berührungs- und Mausereignisse sind exklusiv. Dies kann also etwas dazu beitragen, verschiedene Maßnahmen zu ergreifen. Das Problem ist, dass die Berührungsereignisse näher an den Mausereignissen für Auf / Ab / Verschieben liegen und auch ein Klickereignis auslösen.

Aus Ihrer Frage geht hervor, dass Sie einen Schwebeflug zur Vorschau haben möchten. Darüber hinaus kenne ich keine weiteren Details zu Ihrer Benutzeroberfläche. Ich gehe davon aus, dass Sie mit fehlender Maus eine Vorschau für das Tippen wünschen, während ein Klick aufgrund der Hover-Vorschau eine andere Aktion ausführt.

Wenn dies der Fall ist, können Sie bei der Erkennung etwas faul vorgehen:

Einem Onclick-Ereignis geht immer ein Onmouseover-Ereignis mit der Maus voraus. Notieren Sie sich also, dass sich die Maus über dem Element befindet, auf das geklickt wurde.

Sie können dies mit einem dokumentweiten Ereignis zum Entfernen von Dateien tun. Sie können event.targetdamit aufzeichnen, auf welchem ​​Element sich die Maus befindet. Anschließend können Sie in Ihren Onclick-Ereignissen überprüfen, ob sich die Maus tatsächlich über dem Element befindet, auf das geklickt wird (oder einem untergeordneten Element des Elements).

Von dort aus können Sie wählen, ob Sie sich für beide auf das Klickereignis verlassen und je nach Ergebnis eine A- oder B-Aktion ausführen möchten. Die B-Aktion kann nichts sein, wenn einige Touch-Geräte kein Klickereignis ausgeben (stattdessen müssten Sie sich auf ontouch * -Ereignisse verlassen).

Luke
quelle
0

Ich glaube nicht, dass es möglich ist, nur Touch-Geräte zu identifizieren (meines Wissens natürlich). Das Hauptproblem ist, dass alle Maus- und Tastaturereignisse auch von Touch-Geräten ausgelöst werden. Im folgenden Beispiel geben beide Warnungen für Touch-Geräte true zurück.

function is_touch_present() {
  return ('ontouchstart' in window) || ('onmsgesturechange' in window);
}

function is_mouse_present() {
  return (('onmousedown' in window) && ('onmouseup' in window) && ('onmousemove' in window) && ('onclick' in window) && ('ondblclick' in window) && ('onmousemove' in window) && ('onmouseover' in window) && ('onmouseout' in window) && ('oncontextmenu' in window));
}

alert("Touch Present: " + is_touch_present());
alert("Mouse Present: " + is_mouse_present());
Bikas
quelle
2
Safari iPad kehrt zurück truefür'onmousedown' in window
vsync
0

Die beste Idee ist meiner Meinung nach die mousemove Hörer (derzeit die beste Antwort). Ich glaube, dass diese Methode ein wenig optimiert werden muss. Es ist wahr, dass berührungsbasierte Browser sogar das Mausbewegungsereignis emulieren, wie Sie in dieser iOS-Diskussion sehen können. Daher sollten wir ein wenig vorsichtig sein.

Es ist sinnvoll, dass berührungsbasierte Browser dieses Ereignis nur emulieren, wenn der Benutzer auf den Bildschirm tippt (der Finger des Benutzers ist gedrückt). Dies bedeutet, dass wir während unseres Mausbewegungs-Handlers einen Test hinzufügen sollten, um festzustellen, welche Maustaste während des Ereignisses gedrückt ist (falls vorhanden). Wenn keine Maustaste gedrückt ist, können wir davon ausgehen, dass eine echte Maus vorhanden ist. Wenn eine Maustaste gedrückt ist, bleibt der Test nicht schlüssig.

Wie würde dies umgesetzt werden? Dies Frage zeigt, dass die zuverlässigste Methode, um zu untersuchen, welche Maustaste während einer Mausbewegung gedrückt ist, darin besteht, tatsächlich auf drei Ereignisse auf Dokumentebene zu warten: Mausbewegung, Mausbewegung und Mausbewegung. Das Auf und Ab setzt nur ein globales Boolesches Flag. Der Umzug führt den Test durch. Wenn Sie einen Zug haben und der Boolesche Wert falsch ist, können wir davon ausgehen, dass eine Maus vorhanden ist. Siehe Frage für genaue Codebeispiele.

Ein letzter Kommentar. Dieser Test ist nicht ideal, da er nicht in der Ladezeit durchgeführt werden kann. Daher würde ich eine progressive Verbesserungsmethode verwenden, wie zuvor vorgeschlagen. Standardmäßig wird eine Version angezeigt, die die mausspezifische Hover-Oberfläche nicht unterstützt. Wenn eine Maus erkannt wird, aktivieren Sie diesen Modus zur Laufzeit mit JS. Dies sollte dem Benutzer so nahtlos wie möglich erscheinen.

Um Änderungen in der Benutzerkonfiguration zu unterstützen (dh die Maus wurde getrennt), können Sie sie regelmäßig erneut testen. Obwohl ich glaube, dass es in diesem Fall besser ist, den Benutzer einfach über die beiden Modi zu informieren und die Benutzer manuell zwischen ihnen wechseln zu lassen (ähnlich wie bei der Auswahl für Mobilgeräte / Desktops, die immer rückgängig gemacht werden kann).

talkol
quelle
Vielen Dank für die guten Vorschläge zur Problemumgehung ... Ich denke, das Hauptproblem, das nicht gelöst wird, ist, dass ich auf eines davon zurückgreifen muss
Samuel Rossille
Leider wird die Mausbewegung beim Klicken auf ein iPad ausgelöst. Nur mit Simulator getestet. Für hasMouse () habe ich if (! ('Ontouchstart' im Fenster)) verwendet. Return true; funktioniert aber nicht für Touch-unterstützte Laptops.
Chris Gunawardena
@ Chris G - iPad Hölle ... (schlug meinen Kopf gegen die Wand)
vsync
0

Es wurden einige Tests auf verschiedenen PCs, Linux-, iPhone-, Android-Handys und Registerkarten durchgeführt. Seltsam, dass es keine einfache kugelsichere Lösung gibt. Das Problem tritt auf, wenn einige Benutzer mit Touch und keiner Maus Touch- und Mausereignisse für die Anwendung anzeigen. Da Sie Instanzen nur mit der Maus und nur mit der Berührung unterstützen möchten, möchten Sie beide verarbeiten, dies führt jedoch zu doppeltem Auftreten von Benutzerinteraktionen. Wenn Sie wissen, dass keine Maus auf dem Gerät vorhanden ist, können Sie falsche / eingefügte Mausereignisse ignorieren. Versucht, das Flag zu setzen, wenn MouseMove angetroffen wird, aber einige Browser fälschen MouseMove sowie MouseUp und MouseDown auslösen. Ich habe versucht, Zeitstempel zu untersuchen, fand das aber zu riskant. Fazit: Ich habe festgestellt, dass die Browser, die die gefälschten Mausereignisse erstellt haben, immer einen einzelnen MouseMove unmittelbar vor dem eingefügten MouseDown eingefügt haben. In 99,99% meiner Fälle Wenn Sie auf einem System mit einer echten Maus ausgeführt werden, gibt es mehrere aufeinanderfolgende MouseMove-Ereignisse - mindestens zwei. Verfolgen Sie also, ob das System auf zwei aufeinanderfolgende MouseMove-Ereignisse stößt, und erklären Sie, dass keine Maus vorhanden ist, wenn diese Bedingung nie erfüllt ist. Dies ist wahrscheinlich zu einfach, funktioniert aber bei allen meinen Test-Setups. Ich denke, ich bleibe dabei, bis ich eine bessere Lösung gefunden habe. - Jim W.

jwasch
quelle
0

Eine einfache Lösung in jQuery zur Erkennung der Mausnutzung, die das Problem löst, bei dem mobile Geräte auch das Ereignis "Mausbewegung" auslösen. Fügen Sie einfach einen Touchstart-Listener hinzu, um den Mousemove-Listener zu entfernen, damit er bei Berührung nicht ausgelöst wird.

$('body').one('touchstart.test', function(e) {
  // Remove the mousemove listener for touch devices
  $('body').off('mousemove.test');
}).one('mousemove.test', function(e) {
  // MOUSE!
});

Natürlich könnte das Gerät immer noch Touch AND Mouse sein, aber das oben Gesagte garantiert, dass eine echte Maus verwendet wurde.

suncat100
quelle
0

Ich habe gerade eine Lösung gefunden, die ich für ziemlich elegant halte.

// flag as mouse interaction by default
var isMouse = true;

// detect a touch event start and flag it
$(window).on('touchstart', function () {
  // if triggers touchstart, toggle flag
  // since touch events come before mouse event / click
  // callback of mouse event will get in callback
  // `isMouse === false`
  isMouse = false;
});

// now the code that you want to write
// should also work with `mouse*` events
$('a.someClass').on('click', function () {
  if (isMouse) {
    // interaction with mouse event
    // ...
  } else {
    // reset for the next event detection
    // this is crucial for devices that have both
    // touch screen and mouse
    isMouse = true;

    // interaction with touch event
    // ...
  }
});
Koala Yeung
quelle
0

Ich bin auf dasselbe Problem gestoßen, bei dem eine einzelne Berührung auch als Klick registriert wurde. Nachdem ich die Kommentare der am besten bewerteten Antworten durchgelesen hatte, kam ich auf meine eigene Lösung:

var body = document.getElementsByTagName('body')[0];
var mouseCount = 0;

// start in an undefined state 
// (i use this to blend in elements once we decide what input is used)
var interactionMode = 'undefined';


var registerMouse = function() {
  // count up mouseCount every time, the mousemove event is triggered
  mouseCount++;

  // but dont set it instantly. 
  // instead wait 20 miliseconds (seems to be a good value for multiple move actions), 
  // if another mousemove event accoures switch to mouse as interaction 
  setTimeout(function() {
    // a touch event triggers also exactly 1 mouse move event.
    // So only if mouseCount is higher than 1 we are really moving the cursor by mouse.
    if (mouseCount > 1) {
      body.removeEventListener('mousemove', registerMouse);
      body.removeEventListener('touchend', registerTouch);

      interactionMode = 'mouse';
      console.log('now mousing');
      listenTouch();
    }

    // set the counter to zero again
    mouseCount = 0;
  }, 20);
};

var registerTouch = function() {
  body.removeEventListener('mousemove', registerMouse);
  body.removeEventListener('touchend', registerTouch);

  interactionMode = 'touch';
  console.log('now touching');
  mouseCount = 0;

  listenMouse();
};

var listenMouse = function() {
  body.addEventListener("mousemove", registerMouse);
};
var listenTouch = function() {
  body.addEventListener("touchend", registerTouch);
};

listenMouse();
listenTouch();

// after one second without input, assume, that we are touching
// could be adjusted to several seconds or deleted
// without this, the interactionMode would stay 'undefined' until first mouse or touch event
setTimeout(function() {
  if (!body.classList.contains('mousing') || body.classList.contains('touching')) {
    registerTouch();
  }
}, 1000);
/* fix, so that scrolling is possible */

html,
body {
  height: 110%;
}
Mouse or touch me

Das einzige Problem, das ich gefunden habe, ist, dass Sie scrollen können müssen, um ein Berührungsereignis richtig zu erkennen. Eine einzelne Registerkarte (Berührung) kann Probleme verursachen.

Jannis Nexor Ianus Betz
quelle
0

Ich habe Stunden damit verbracht, dieses Problem für meine Phonegap-App herauszufinden, und mir diesen Hack ausgedacht. Es generiert eine Konsolenwarnung, wenn das ausgelöste Ereignis ein "passives" Ereignis ist, was bedeutet, dass es keine Änderung auslöst, aber es funktioniert! Ich würde mich für Verbesserungsvorschläge oder eine bessere Methode interessieren. Dies ermöglicht mir jedoch effektiv, $ .touch () universell zu verwenden.

$(document).ready(function(){
  $("#aButton").touch(function(origElement, origEvent){
    console.log('Original target ID: ' + $(origEvent.target).attr('id'));
  });
});

$.fn.touch = function (callback) {
    var touch = false;
    $(this).on("click", function(e){
        if (!touch)
        {
            console.log("I click!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }else{
            touch = true;
        }
        touch = false;
    });
    $(this).on("touchstart", function(e){
        if (typeof e.touches != typeof undefined)
        {
            e.preventDefault();
            touch = true;
            console.log("I touch!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id="aButton">A Button</button>

Jay
quelle
0

Das Hauptproblem, das ich hier sehe, ist, dass die meisten Touch-Geräte ein Mausereignis zusammen mit dem entsprechenden Touch-Ereignis auslösen (Touchstart -> Mousedown, Touchmove -> Mousemove usw.). Nur für die Tastatur, zuletzt für die modernen, verfügen sie über einen generischen Browser, sodass Sie nicht einmal das Vorhandensein der MouseEvent-Klasse erkennen können.

Die weniger schmerzhafte Lösung wäre meiner Meinung nach, beim Start ein Menü anzuzeigen (mit 'Alt'-Verwaltung nur für Benutzer mit Tastatur) und die Auswahl möglicherweise mit localStorage / cookies / serverside zu speichern oder die gleiche Auswahl beim nächsten Mal beizubehalten Mal kommt der Besucher.

Ernoriel
quelle
-4

Ich würde dringend gegen diesen Ansatz empfehlen. Betrachten Sie Geräte mit Touchscreen und Desktop-Größe, und Sie müssen verschiedene Probleme lösen.

Bitte machen Sie Ihre App ohne Maus nutzbar (dh keine Schwebevorschau).

Chris Broadfoot
quelle
1
Genau das versuche ich zu tun. Ich versuche, eine Schnittstelle zu erstellen, die auf beiden Tablets (keine Maus) und mit einer Maus bestmöglich funktioniert, aber diese Schnittstellen sind notwendigerweise sehr unterschiedlich.
Jon Gjengset
Ich stimme Broady zu. Verwenden Sie am besten eine Geräteerkennung (wie DeviceAtlas) und wählen Sie beim Laden die angebotene Schnittstelle aus.
Teemu Ikonen
-4

Ich möchte ein Skript empfehlen, das mir geholfen hat:

Ich hatte alles, was vorgeschlagen wurde, gelesen und ausprobiert, ohne ausreichende Ergebnisse.

Dann habe ich noch etwas nachgeforscht und diesen Code gefunden - device.js

Ich verwende dies auf der Website meines Kunden, um die Existenz von Mäusen zu erkennen:
( <html>sollte desktopKlasse haben) und es scheint ziemlich gut zu sein, und zur touchUnterstützung mache ich einfach die regelmäßige Überprüfung 'ontouchend' in documentund verwende die Informationen beider Erkennungen, um eine bestimmte Sache anzunehmen, die ich brauche.

vsync
quelle
Das ist gleichbedeutend mit UA-Schnüffeln, das in diesem Thema bereits mehrfach angesprochen wurde. Es löst den Fall von Geräten mit Maus UND Touch wie Windows 8 nicht und ist definitiv nicht zukunftssicher.
Hugo Silva
Ich benutze es, um diesen GENAUEN Fall zu lösen, den Sie in der Anwendung eines Kunden erwähnt haben, und es funktioniert gut. Es ist zukunftssicher, da es vom Entwickler gewartet wird.
vsync
2
Der von mir erwähnte Fall (Touch-fähiger Laptop) wird von Ihrem Skript als "Desktop" identifiziert, obwohl ich möglicherweise keine Maus verwenden kann. "Es ist zukunftssicher, weil es vom Entwickler gepflegt wird" - ich denke, Sie haben den Punkt "zukunftssicher" hier völlig übersehen. Und wenn Sie alles so gelesen und ausprobiert hätten, wie Sie es angegeben haben, hätten Sie bemerkt, dass Gigis Antwort bereits darauf hindeutet, dass UA schnüffelt.
Hugo Silva
-7

Im Allgemeinen ist es besser zu erkennen, ob die Mouseover-Funktion unterstützt wird, als den Betriebssystem- / Browsertyp zu erkennen. Sie können dies einfach folgendermaßen tun:

if (element.mouseover) {
    //Supports the mouseover event
}

Stellen Sie sicher, dass Sie Folgendes nicht tun:

if (element.mouseover()) {
    // Supports the mouseover event
}

Letzterer würde die Methode tatsächlich aufrufen, anstatt ihre Existenz zu überprüfen.

Weitere Informationen finden Sie hier: http://www.quirksmode.org/js/support.html

Marcus Swope
quelle
2
Ich weiß nicht wirklich, was ich von Ihrem Beitrag bekommen soll, aber wenn ('onmouseover' in $ ('body') [0]) alert ('onmouseover'); zeigt eine Nachricht auch im iPhone an
nraynaud
1
Dies prüft nur, ob die Mouseover-Funktion definiert ist, wie dies bei fast allen Browsern der Fall wäre. Es wird nicht erkannt, ob tatsächlich eine Maus vorhanden ist.
Jon Gjengset