Wie erhalte ich die Mausposition ohne Ereignisse (ohne die Maus zu bewegen)?

286

Ist es möglich, die Mausposition mit JavaScript nach dem Laden der Seite ohne Mausbewegungsereignis (ohne Bewegung der Maus) zu ermitteln?

Norbert Tamas
quelle
61
An dem Mousemove-Ereignis ist nichts auszusetzen. Nur in einigen Fällen bewegen Benutzer die Maus nicht. Danke für deine Antwort.
Norbert Tamas
2
Norbert Tamas, die Antwort von @ SuperNova (die erst in diesem Jahr hinzugefügt wurde) zeigt, dass mouseenter hierfür gut funktioniert, da es beim Laden der Seite ausgelöst wird (wenn sich die Maus im Ansichtsfenster befindet). Hat es 2010 nicht so funktioniert, oder hat nur niemand daran gedacht, es zu versuchen?
Peter Hansen
@CrescentFresh In einigen Fällen (wie bei Benutzerskripten) möchten Sie den Browser nicht durch Hinzufügen vieler mousemoveEreignisse verlangsamen .
Tomáš Zato - Wiedereinsetzung Monica
Möglich in FF mit Mouseover, aber nicht in IE und Chrome.
Elad
Oder in einem Spiel bewegt sich Ihre Kamera in der Spielwelt und der Charakter schaut auf die Maus (typischer Top-Down-Shooter-Stil). Wenn der Benutzer jedoch keine Maus bewegt, wird sie beim Bewegen um den falschen Punkt zentriert Sie verlassen sich nur auf Mausbewegung. Es ist jedoch keine große Sache, wir speichern nur die "Welt" -Koordinaten des Zeigers und lassen die Leute das abfragen.
Kamranicus

Antworten:

336

Richtige Antwort: Nein, das ist nicht möglich.

OK, ich habe gerade über einen Weg nachgedacht. Überlagern Sie Ihre Seite mit einem Div, der das gesamte Dokument abdeckt. Erstellen Sie darin beispielsweise 2.000 x 2.000 <a>Elemente (damit die :hoverPseudoklasse in IE 6 funktioniert, siehe), die jeweils 1 Pixel groß sind. Erstellen Sie eine CSS- :hoverRegel für die <a>Elemente, die eine Eigenschaft ändern (z. B. font-family). Durchlaufen Sie in Ihrem Load-Handler jedes der 4 Millionen <a>Elemente und überprüfen Sie currentStyle/, getComputedStyle()bis Sie das Element mit der Hover-Schriftart finden. Extrapolieren Sie von diesem Element zurück, um die Koordinaten innerhalb des Dokuments zu erhalten.

NB TUN SIE DAS NICHT .

Tim Down
quelle
92
ha ha - irgendwann sollten Sie googeln und sehen, ob Sie herausfinden können, wie viele Leute dies tatsächlich implementiert haben
Pointy
6
Eigentlich ist es implementierbar, ohne zu viel CPU-Last zu haben (ich denke. Ich habe es nicht getestet). Erstellen Sie auf dom ready die <a> -Elemente mit Javascript, nehmen Sie die Mausposition und entfernen Sie dann alle <a> -Elemente. Bei einer Maus sollten Sie eine andere Funktion haben, um die Mausposition einzunehmen. Wie auch immer, das war komisch.
Machineaddict
21
Vielleicht könnte dies mit der binären Suche praktisch gemacht werden? Schleife, die ein Elementpaar erstellt <a>, das bestimmte Rechtecke abdeckt ( <img>vermutlich unter absoluter Positionierung von Größenelementen), wobei die Rechtecke jedes Mal verkleinert werden. Ja, es ist lächerlich, aber es ist nicht möglich, diese Informationen vor dem ersten Mauszug zu erhalten.
Darius Bacon
29
stackoverflow.com/a/8543879/27024 sagt, dass der Hover auch nicht ausgelöst wird , bis sich die Maus zum ersten Mal bewegt. Dies vereitelt dieses Schema.
Darius Bacon
4
@DariusBacon: Diese verknüpfte Antwort scheint nicht korrekt zu sein: jsbin.com/utocax/3 . Ja, dieser Ansatz kann in einigen Situationen praktisch sein.
Tim Down
121

Edit 2020: Das funktioniert nicht mehr. Es scheint so, dass die Browser-Anbieter dies behoben haben. Da die meisten Browser auf Chrom setzen, befindet es sich möglicherweise in seinem Kern.

Alte Antwort: Sie können auch mouseenter einbinden (dieses Ereignis wird nach dem erneuten Laden der Seite ausgelöst, wenn sich der Mauszeiger innerhalb der Seite befindet). Das Erweitern des Codes von Corrupted sollte den Trick machen:

var x = null;
var y = null;
    
document.addEventListener('mousemove', onMouseUpdate, false);
document.addEventListener('mouseenter', onMouseUpdate, false);
    
function onMouseUpdate(e) {
  x = e.pageX;
  y = e.pageY;
  console.log(x, y);
}

function getMouseX() {
  return x;
}

function getMouseY() {
  return y;
}

Sie können x und y auch bei einem Mausblattereignis auf null setzen. So können Sie mit dem Cursor überprüfen, ob sich der Benutzer auf Ihrer Seite befindet.

SuperNova
quelle
11
Dies scheint hier die einzig wirklich nützliche Antwort zu sein, was seltsam erscheint. In der Tat (in den neuesten Versionen von Firefox, Chrome und IE11) wird der Mouseenter beim Laden der Seite ausgelöst und gibt die richtigen Koordinaten an. Hat sich das Browserverhalten in diesem Bereich in den letzten Jahren einfach geändert?
Peter Hansen
3
Tatsächlich scheint "mouseenter" keinen Mehrwert zu bieten. Ich habe mit der folgenden jsfiddle in Chrome und IE getestet und sie zeigen die Koordinaten erst an, wenn Sie die Maus auf das innere Dokument (das Ergebnisfenster) setzen: jsfiddle.net/xkpd784o/1
Mariano Desanze
1
@Proton: Bewegen Sie Ihre Maus zum Ergebnisfenster in den Bereich des Ergebnisfensters, BEVOR die Seite vollständig geladen wurde und bewegen Sie sich nicht als. Nach dem Laden kennt die Seite sofort die Position der Maus. Es ist keine Mausbewegung erforderlich. Mouseenter wird also auch ausgelöst, wenn die Seite geladen wurde und sich die Maus im Dokumentbereich befindet. Das wollte das OP ursprünglich. Niemand anderes gibt diese Antwort.
SuperNova
1
Eine potenziell nützliche Ergänzung ist eine Funktion für den hinzuzufügen mouseleaveFall , dass Sätze xund yzurück zu nulloder'undefined'
rtpax
2
In Chrome 68 wird bei Verwendung des obigen jsfiddel-Alarms beim ersten Bewegen der Maus und nicht beim Laden eine Warnung angezeigt, selbst wenn die Maus in den gerenderten Bereich bewegt wird, bevor die Seite vollständig geladen wurde.
Junvar
84

Sie können Variablen für die xund die yKoordinaten Ihres Cursors erstellen , diese aktualisieren, wenn sich die Maus bewegt, und eine Funktion in einem Intervall aufrufen, um mit der gespeicherten Position das zu tun, was Sie benötigen.

Der Nachteil dabei ist natürlich, dass mindestens eine erste Bewegung der Maus erforderlich ist, damit sie funktioniert. Solange der Cursor seine Position mindestens einmal aktualisiert, können wir seine Position finden, unabhängig davon, ob er sich wieder bewegt.

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}
setInterval(checkCursor, 1000);
function checkCursor(){
    alert("Cursor at: " + cursorX + ", " + cursorY);
}

Der vorhergehende Code wird einmal pro Sekunde mit einer Meldung aktualisiert, wo sich Ihr Cursor befindet. Ich hoffe das hilft.

JHarding
quelle
18
Hast du das Thema dieses Beitrags gelesen? Das OP fragt, wie die Mauskoordinaten ohne Verwendung eines Ereignisses abgerufen werden sollen. In Ihrem Beitrag wird jedoch vorgeschlagen, das Ereignis onmousemove zu verwenden.
Jake
53
@jake Obwohl das OP speziell nach einer Nicht-Ereignis-Methode gefragt hat, kommt diese Antwort anderen zugute, die hierher gekommen sind, um eine Antwort und möglicherweise eine Problemumgehung zu finden. Außerdem würde ich diese Antwort teilweise innerhalb des Themas betrachten, da dies meines Wissens die beste Methode ist, um die Cursorposition zu einem bestimmten Zeitpunkt zu ermitteln, ohne Ereignisse direkt verwenden zu müssen. Die Antwort hätte jedoch eher so formuliert werden können, dass sie die Tatsache darlegt und einen Weg bietet, um zu vermeiden, dass Kommentare nicht ausgewählt werden.
jpeltoniemi
2
@Pichan Es hat mir nicht geholfen, weil ich nach einer Möglichkeit gesucht habe, diese cursorX/YVariablen zu füllen , bevor ein Ereignis eintritt.
polkovnikov.ph
Sehr wenige Benutzer werden keine Mausereignisse
auslösen
1
Vorsicht, es kann kostspielig sein, einen Mousemove-Hörer in der Nähe zu halten. Ich würde vorschlagen, den Listener in dem Intervall neu zu erstellen und den Listener zu zerstören, nachdem Sie die Koordinaten erhalten haben.
KRB
10

Sie könnten etwas Ähnliches ausprobieren, wie Tim Down vorgeschlagen hat - aber anstatt Elemente für jedes Pixel auf dem Bildschirm zu haben, erstellen Sie nur 2-4 Elemente (Kästchen) und ändern Sie deren Position, Breite und Höhe dynamisch, um die noch möglichen Positionen auf dem Bildschirm zu teilen um 2-4 rekursiv, wodurch die reale Position der Maus schnell gefunden wird.

Zum Beispiel - erste Elemente nehmen die rechte und linke Hälfte des Bildschirms ein, danach die obere und untere Hälfte. Inzwischen wissen wir bereits, in welchem ​​Viertel des Bildschirms sich die Maus befindet, können wiederholen - entdecken Sie, welches Viertel dieses Raumes ...

AlexTR
quelle
9

Die Antwort von @Tim Down ist nicht performant, wenn Sie 2.000 x 2.000 <a>Elemente rendern :

OK, ich habe gerade über einen Weg nachgedacht. Überlagern Sie Ihre Seite mit einem Div, der das gesamte Dokument abdeckt. Erstellen Sie darin beispielsweise 2.000 x 2.000 Elemente (damit die: hover-Pseudoklasse in IE 6 funktioniert, siehe) mit jeweils 1 Pixel Größe. Erstellen Sie eine CSS: Hover-Regel für die Elemente, die eine Eigenschaft ändern (z. B. Schriftfamilie). Durchlaufen Sie in Ihrem Load-Handler jedes der 4 Millionen Elemente und überprüfen Sie currentStyle / getComputedStyle (), bis Sie das mit der Hover-Schriftart finden. Extrapolieren Sie von diesem Element zurück, um die Koordinaten innerhalb des Dokuments zu erhalten.

NB TUN SIE DAS NICHT.

Sie müssen jedoch nicht 4 Millionen Elemente gleichzeitig rendern, sondern die binäre Suche verwenden. Verwenden Sie <a>stattdessen einfach 4 Elemente:

  • Schritt 1: Betrachten Sie den gesamten Bildschirm als Startsuchbereich
  • Schritt 2: Split der Suchbereich in 2 x 2 = 4 Rechteck - <a>Elemente
  • Schritt 3: getComputedStyle()Bestimmen Sie mithilfe der Funktion, in welchem ​​Rechteck sich die Maus befindet
  • Schritt 4: Reduzieren Sie den Suchbereich auf dieses Rechteck und wiederholen Sie den Vorgang ab Schritt 2.

Auf diese Weise müssten Sie diese Schritte maximal elf Mal wiederholen, da Ihr Bildschirm nicht breiter als 2048 Pixel ist.

Sie generieren also maximal 11 x 4 = 44 <a>Elemente.

Wenn Sie die Mausposition nicht genau auf ein Pixel genau bestimmen müssen, aber sagen, dass eine Genauigkeit von 10 Pixel in Ordnung ist. Sie würden die Schritte höchstens 8 Mal wiederholen, sodass Sie maximal 8 x 4 = 32 <a>Elemente zeichnen müssten .

Auch das Erzeugen und anschließende Zerstören der <a>Elemente wird nicht ausgeführt, da DOM im Allgemeinen langsam ist. Stattdessen können Sie nur die ersten 4 wiederzuverwenden <a>Elemente und nur ihre anpassen top, left, widthund heightwie Sie Schleife durch die Schritte.

Jetzt ist das Erstellen von 4 ebenfalls <a>ein Overkill. Stattdessen können Sie dasselbe <a>Element beim Testen getComputedStyle()in jedem Rechteck wiederverwenden . Anstatt den Suchbereich in 2 x 2 <a>Elemente aufzuteilen, verwenden Sie einfach ein einzelnes <a>Element, indem Sie es mit den Stil- topund leftStileigenschaften verschieben.

Alles, was Sie brauchen, ist ein einzelnes <a>Element, das seine widthund heightmax 11-mal und seine topund leftmax 44-mal ändert, und Sie haben die genaue Mausposition.

Alex Peterson
quelle
3

Die einfachste Lösung, aber nicht 100% genau

$(':hover').last().offset()

Ergebnis: {top: 148, left: 62.5}
Das Ergebnis hängt von der nächstgelegenen Elementgröße ab und wird zurückgegeben, undefinedwenn der Benutzer die Registerkarte wechselt

StefansArya
quelle
Für mich kehrt es undefinedtrotzdem zurück. Können Sie erläutern, wie dies zu verwenden ist?
Tresf
Es wird zurückgegeben, undefinedwenn der Cursor kein Element bewegt (oder wenn der Browser den Fokus verloren hat). Möglicherweise müssen Sie ein Zeitintervall festlegen, wenn Sie von der Konsole aus testen.
StefansArya
Vielen Dank. setTimeouthat funktioniert. Ich habe jsfiddle verwendet und Sie haben Recht, es hat nie ein Schwebeflugereignis getroffen, da es das DOM jedes Mal neu zeichnet, wenn Sie auf Wiedergabe klicken. Ich würde empfehlen, diesen Hinweis für andere hinzuzufügen.
Tresf
Ich möchte keine genaue Mausposition, aber ich möchte nur wissen, dass die Maus ganz rechts oder ganz links ohne Ereignisobjekt funktioniert, damit Ihre Lösung in meinem Fall funktioniert. Danke
Swap-IOS-Android
2

Ich stelle mir vor, dass Sie möglicherweise eine übergeordnete Seite mit einem Timer haben und den Benutzer nach einer bestimmten Zeit oder nach Abschluss einer Aufgabe auf eine neue Seite weiterleiten. Jetzt möchten Sie die Cursorposition und weil sie warten, berühren sie nicht unbedingt die Maus. Verfolgen Sie also die Maus auf der übergeordneten Seite mithilfe von Standardereignissen und übergeben Sie den letzten Wert in einer get- oder post-Variablen an die neue Seite.

Sie können den JHarding-Code auf Ihrer übergeordneten Seite verwenden, sodass die neueste Position immer in einer globalen Variablen verfügbar ist:

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}

Dies hilft Benutzern nicht, die mit anderen Mitteln als Ihrer übergeordneten Seite zu dieser Seite navigieren.


quelle
1

Ich habe eine horizontale / vertikale Suche implementiert (erst ein Div voller vertikal angeordneter vertikaler Linienverknüpfungen, dann ein Div voll vertikal angeordneter horizontaler Linienverknüpfungen und einfach sehen, welche den Schwebezustand hat), wie Tim Downs Idee oben, und es funktioniert ziemlich schnell. Funktioniert leider nicht auf Chrome 32 unter KDE.

jsfiddle.net/5XzeE/4/

user2958613
quelle
Anscheinend funktionieren diese Tricks nur, wenn der Benutzer eine explizite Mausbewegung ausführt. :(
trusktr
1

Sie müssen die Maus nicht bewegen , um die Position des Cursors zu ermitteln. Der Standort wird auch über andere Ereignisse als Mausbewegungen gemeldet . Hier ist ein Klickereignis als Beispiel:

document.body.addEventListener('click',function(e)
{
    console.log("cursor-location: " + e.clientX + ',' + e.clientY);
});
Lonnie Best
quelle
1

In Anlehnung an die Antwort von @ SuperNova finden Sie hier einen Ansatz, bei dem ES6-Klassen verwendet werden, um den Kontext thisin Ihrem Rückruf korrekt zu halten:

class Mouse {
  constructor() {
    this.x = 0;
    this.y = 0;
    this.callbacks = {
      mouseenter: [],
      mousemove: [],
    };
  }

  get xPos() {
    return this.x;
  }

  get yPos() {
    return this.y;
  }

  get position() {
    return `${this.x},${this.y}`;
  }

  addListener(type, callback) {
    document.addEventListener(type, this); // Pass `this` as the second arg to keep the context correct
    this.callbacks[type].push(callback);
  }

  // `handleEvent` is part of the browser's `EventListener` API.
  // https://developer.mozilla.org/en-US/docs/Web/API/EventListener/handleEvent
  handleEvent(event) {
    const isMousemove = event.type === 'mousemove';
    const isMouseenter = event.type === 'mouseenter';

    if (isMousemove || isMouseenter) {
      this.x = event.pageX;
      this.y = event.pageY;
    }

    this.callbacks[event.type].forEach((callback) => {
      callback();
    });
  }
}

const mouse = new Mouse();

mouse.addListener('mouseenter', () => console.log('mouseenter', mouse.position));
mouse.addListener('mousemove', () => console.log('mousemove A', mouse.position));
mouse.addListener('mousemove', () => console.log('mousemove B', mouse.position));

Patrick Berkeley
quelle
1

Hier ist meine Lösung. Es exportiert die Eigenschaften window.currentMouseX und window.currentMouseY, die Sie überall verwenden können. Es verwendet zunächst die Position eines schwebenden Elements (falls vorhanden) und hört anschließend Mausbewegungen ab, um die richtigen Werte festzulegen.

(function () {
    window.currentMouseX = 0;
    window.currentMouseY = 0;

    // Guess the initial mouse position approximately if possible:
    var hoveredElement = document.querySelectorAll(':hover');
    hoveredElement = hoveredElement[hoveredElement.length - 1]; // Get the most specific hovered element

    if (hoveredElement != null) {
        var rect = hoveredElement.getBoundingClientRect();
        // Set the values from hovered element's position
        window.currentMouseX = window.scrollX + rect.x;
        window.currentMouseY = window.scrollY + rect.y;
    }

    // Listen for mouse movements to set the correct values
    document.addEventListener('mousemove', function (e) {
        window.currentMouseX = e.pageX;
        window.currentMouseY = e.pageY;
    });
}())

Composr CMS- Quelle: https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

Salman von Abbas
quelle
0
var x = 0;
var y = 0;

document.addEventListener('mousemove', onMouseMove, false)

function onMouseMove(e){
    x = e.clientX;
    y = e.clientY;
}

function getMouseX() {
    return x;
}

function getMouseY() {
    return y;
}
Beschädigt
quelle
14
Muss der Benutzer die Maus nicht noch bewegen?
Paul Hiemstra
0

Ich denke, ich habe vielleicht eine vernünftige Lösung, ohne Divs und Pixel zu zählen

Verwenden Sie einfach einen Animationsrahmen oder ein Zeitintervall einer Funktion. Sie benötigen zwar einmal ein Mausereignis, um es zu initiieren, aber technisch positionieren Sie dieses, wo immer Sie möchten.

Im Wesentlichen verfolgen wir jederzeit ein Dummy-Div ohne Mausbewegung.

// create a div(#mydiv) 1px by 1px set opacity to 0 & position:absolute;

Unten ist die Logik ..

var x,y;


$('body').mousemove(function( e ) {

    var x = e.clientX - (window.innerWidth / 2);
    var y = e.clientY - (window.innerHeight / 2);
 }


function looping (){

   /* track my div position 60 x 60 seconds!
      with out the mouse after initiation you can still track the dummy div.x & y
      mouse doesn't need to move.*/

   $('#mydiv').x = x;    // css transform x and y to follow 
   $('#mydiv)'.y = y;

   console.log(#mydiv.x etc)

   requestAnimationFrame( looping , frame speed here);
}  
Joshua
quelle