Как получить положение мыши без событий (без перемещения мыши)?

286

Можно ли получить положение мыши с помощью JavaScript после загрузки страницы без какого-либо события перемещения мыши (без перемещения мыши)?

Норберт Тамас
источник
61
Ничего плохого в событии mousemove. Просто в некоторых случаях пользователи не двигают мышь. Спасибо за Ваш ответ.
Норберт Тамас
2
Норберт Тамас, ответ @ SuperNova (который не был добавлен до этого года) показывает, что mouseenter отлично работает для этого, потому что он срабатывает при загрузке страницы (если мышь находится в области просмотра). Разве это не сработало в 2010 году или просто никто не подумал попробовать?
Питер Хансен
@CrescentFresh В некоторых случаях (например, пользовательские скрипты) вы не хотите замедлять работу браузера, добавляя много mousemoveсобытий.
Томаш Зато - Восстановить Монику
Возможно в FF с наведением мыши, но не в IE и Chrome.
Elad
Или, в игре, ваша камера перемещается по игровому миру, и персонаж смотрит на мышь (типичный стиль стрелялки сверху вниз), но если пользователь не перемещает мышь, он центрируется вокруг неправильной точки, когда вы перемещаетесь, если Вы полагаетесь только на мышиный ход. Тем не менее, это не имеет большого значения, мы просто сохраняем "мировые" координаты указателя и позволяем людям делать это
kamranicus

Ответы:

336

Реальный ответ: нет, это невозможно.

Хорошо, я только что придумал способ. Наложите свою страницу с div, который покрывает весь документ. Внутри этого создайте (скажем) 2000 x 2000 <a>элементов (чтобы :hoverпсевдокласс работал в IE 6, см.), Каждый размером 1 пиксель. Создайте :hoverправило CSS для тех <a>элементов, которые изменяют свойство (скажем font-family). В вашем обработчике нагрузки циклически просматривайте каждый из 4 миллионов <a>элементов, проверяя currentStyle/, getComputedStyle()пока не найдете тот, который имеет шрифт hover. Экстраполировать обратно из этого элемента, чтобы получить координаты в документе.

NB не делай этого .

Тим Даун
источник
92
ха-ха - в какой-то момент вы должны погуглить и посмотреть, сможете ли вы выяснить, сколько людей на самом деле реализовали это
Pointy
6
На самом деле, это реализуемо без большой нагрузки на процессор (я думаю. Я не тестировал его). Когда все будет готово, соберите элементы <a> с помощью javascript, выберите положение мыши и удалите все элементы <a>. На мышиной мыши у вас должна быть другая функция, чтобы занять позицию мыши. Во всяком случае, это было весело.
Machineaddict
21
Возможно, это можно сделать с помощью бинарного поиска? Цикл создает пару <a>элементов, покрывающих заданные прямоугольники ( <img>я полагаю, используя абсолютное позиционирование размерных элементов), каждый раз сжимая прямоугольники. Да, это смешно, но невозможно получить эту информацию до первого движения мышью.
Дариус Бэкон
29
stackoverflow.com/a/8543879/27024 говорит, что наведение не срабатывает, пока мышь не начнет двигаться в первый раз. Это мешает этой схеме.
Дариус Бэкон
4
@DariusBacon: этот связанный ответ не является правильным: jsbin.com/utocax/3 . Так что да, этот подход может быть практичным для некоторых ситуаций.
Тим Даун
121

Редактировать 2020: это больше не работает. Похоже, что производители браузеров исправили это. Поскольку большинство браузеров полагаются на хром, это может быть в его ядре.

Старый ответ: Вы также можете перехватить указатель мыши (это событие вызывается после перезагрузки страницы, когда курсор мыши находится внутри страницы). Расширение кода Corrupted должно помочь:

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

Вы также можете установить x и y в null для mouseleave-события. Таким образом, вы можете проверить, находится ли пользователь на вашей странице с помощью курсора.

SuperNova
источник
11
Казалось бы, это единственный действительно полезный ответ, который кажется странным. Действительно (в последних версиях Firefox, Chrome и IE11) указатель мыши срабатывает при загрузке страницы и выдает правильные координаты. Изменилось ли поведение браузера в этой области за последние несколько лет?
Питер Хансен
3
На самом деле "mouseenter", кажется, не добавляет никакой ценности. Я тестировал следующие jsfiddle в Chrome и IE, и они не отображают кординаты, пока вы не наведете мышь на внутренний документ (панель результатов): jsfiddle.net/xkpd784o/1
Mariano Desanze
1
@ Proton: наведите указатель мыши на панель результатов, чтобы область панели результатов ДО того, как страница полностью загрузится, и не перемещайте ее. После загрузки страницы сразу узнается положение мыши. Нет движения мыши не требуется. Таким образом, mouseenter также запускается, когда страница загружена и мышь находится внутри области документа. То есть то, что изначально хотел ОП. Никто другой не дает такой ответ.
SuperNova
1
Потенциально полезным дополнением является добавление функции для mouseleaveсобытия, которое устанавливает xи yвозвращается к nullили'undefined'
rtpax
2
chrome 68, используя jsfiddel выше, оповещение появляется при первом перемещении мыши, а не при загрузке, даже если мышь перемещается в отображаемую область до завершения загрузки страницы.
Junvar
84

Что вы можете сделать, это создать переменные xи yкоординаты вашего курсора, обновлять их при каждом перемещении мыши и вызывать функцию с интервалом, чтобы сделать то, что вам нужно, с сохраненной позицией.

Недостатком этого является то, что для его работы требуется как минимум одно начальное движение мыши. Пока курсор обновляет свою позицию хотя бы один раз, мы можем находить его позицию независимо от того, будет ли он снова двигаться.

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

Предыдущий код обновляется раз в секунду сообщением о том, где находится ваш курсор. Надеюсь, это поможет.

JHarding
источник
18
Вы читали тему этого поста? ОП спрашивает, как получить координаты мыши без использования события. Тем не менее, ваш пост предлагает использовать событие onmousemove.
Джейк
53
@jake Несмотря на то, что ОП специально спрашивал о методе, не связанном с событиями, этот ответ полезен тем, кто пришел сюда в поисках ответа и, возможно, обходного пути. Кроме того, я бы рассмотрел этот ответ частично в рамках темы, поскольку, насколько я знаю, это лучший способ получить позицию курсора в любой момент времени без необходимости непосредственного использования событий. Тем не менее, ответ можно было бы сформулировать более точно, констатируя факт и предлагая способ избежать придирки в комментариях.
jpeltoniemi
2
@Pichan Это не принесло мне пользы, потому что я искал способ заполнить эти cursorX/Yпеременные до того, как произойдет какое-либо событие.
polkovnikov.ph
очень немногие пользователи не будут
запускать
1
Осторожно, может быть дорого держать слушателя в движении мыши. Я бы предложил воссоздать слушателя в интервале и уничтожить слушателя после получения координат.
KRB
10

Вы можете попробовать нечто похожее на то, что предложил Тим Даун, но вместо того, чтобы иметь элементы для каждого пикселя на экране, создайте всего 2-4 элемента (поля) и динамически изменяйте их местоположение, ширину и высоту, чтобы разделить все еще возможные места на экране. на 2-4 рекурсивно, таким образом, быстро находя реальное местоположение мыши.

Например - первые элементы занимают правую и левую половину экрана, затем верхнюю и нижнюю. К настоящему времени мы уже знаем, в какой четверти экрана находится мышь, можем повторить - выяснить, какая четверть этого пространства ...

AlexTR
источник
9

Ответ @Tim Down бесполезен, если вы отображаете 2000 x 2000 <a>элементов:

Хорошо, я только что придумал способ. Наложите свою страницу с div, который покрывает весь документ. Внутри этого создайте (скажем) 2000 x 2000 элементов (чтобы псевдокласс: hover работал в IE 6, см.), Каждый размером 1 пиксель. Создайте правило CSS: hover для тех элементов, которые изменяют свойство (скажем, font-family). В вашем обработчике нагрузки циклически просматривайте каждый из 4 миллионов элементов, проверяя currentStyle / getComputedStyle (), пока не найдете тот, который имеет шрифт hover. Экстраполировать обратно из этого элемента, чтобы получить координаты в документе.

NB не делай этого.

Но вам не нужно отображать 4 миллиона элементов одновременно, вместо этого используйте бинарный поиск. Просто используйте <a>вместо этого 4 элемента:

  • Шаг 1: Рассмотрим весь экран как начальную область поиска
  • Шаг 2: Разделите область поиска на 2 x 2 = 4 прямоугольных <a>элемента
  • Шаг 3: Используя getComputedStyle()функцию, определите, в каком прямоугольнике зависает мышь
  • Шаг 4: Уменьшите область поиска до этого прямоугольника и повторите с шага 2.

Таким образом, вам нужно будет повторить эти шаги максимум 11 раз, учитывая, что ваш экран не шире, чем 2048 пикселей.

Таким образом, вы получите максимум 11 x 4 = 44 <a>элемента.

Если вам не нужно точно определять положение мыши с точностью до пикселя, но скажите, что с точностью 10px все в порядке. Вы должны повторить шаги не более 8 раз, поэтому вам нужно нарисовать максимум 8 x 4 = 32 <a>элемента.

Также генерирование и последующее уничтожение <a>элементов не выполняется, так как DOM обычно медленный. Вместо этого, вы можете просто повторно использовать начальные 4 <a>элементов и просто настроить их top, left, widthи heightкак вам проходное шагов.

Теперь создание 4 также <a>является излишним. Вместо этого вы можете повторно использовать один и тот же <a>элемент для проверки getComputedStyle()каждого прямоугольника. Таким образом, вместо того , чтобы расщеплению область поиска в 2 х 2 <a>элементов просто повторно использовать один <a>элемент, перемещая его topи leftсвойства стиля.

Таким образом, все, что вам нужно, это один <a>элемент, изменить его widthи heightмакс. 11 раз, а также изменить его topи leftмакс. 44 раза, и вы получите точное положение мыши.

Алекс Петерсон
источник
3

Самое простое решение, но не на 100% точное

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

Результат: {top: 148, left: 62.5}
результат зависит от размера ближайшего элемента и возвращается, undefinedкогда пользователь переключил вкладку

StefansArya
источник
Для меня это возвращается undefinedнезависимо. Можете ли вы уточнить, как это использовать?
Tresf
Он вернется, undefinedкогда курсор не будет зависать ни от какого элемента (или когда браузер потерял фокус). Возможно, вам придется установить временной интервал, если вы проводите тестирование с консоли.
StefansArya
Спасибо. setTimeoutработал. Я использовал jsfiddle, и вы правы, он никогда не срабатывал при наведении курсора, потому что он перерисовывает DOM каждый раз, когда вы нажимаете play. Я бы порекомендовал добавить этот совет другим.
Tresf
Мне не нужна точная позиция мыши, но я просто хочу знать, что мышь находится в крайнем правом или крайнем левом положении в функции без объекта события, поэтому ваше решение работает в моем случае ... спасибо
Swap-IOS-Android
2

Я предполагаю, что, возможно, у вас есть родительская страница с таймером, и по истечении определенного времени или задачи вы перенаправляете пользователя на новую страницу. Теперь вам нужно положение курсора, и поскольку они ждут, они не обязательно касаются мыши. Поэтому отслеживайте мышь на родительской странице, используя стандартные события, и передайте последнее значение новой странице в переменной get или post.

Вы можете использовать код JHarding на своей родительской странице, чтобы последняя позиция всегда была доступна в глобальной переменной:

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

Это не поможет пользователям, которые переходят на эту страницу другими способами, кроме вашей родительской страницы.


источник
1

Я реализовал поиск по горизонтали / вертикали (сначала сделайте div, заполненный ссылками вертикальной линии, расположенными горизонтально, затем сделайте div, заполненный ссылками горизонтальной линии, расположенными вертикально, и просто посмотрите, какая из них имеет состояние наведения), как идея Тима Дауна выше, и это работает довольно быстро. К сожалению, не работает на Chrome 32 на KDE.

jsfiddle.net/5XzeE/4/

user2958613
источник
по-видимому, эти приемы больше не работают, если пользователь явно не перемещает мышь. :(
trusktr
1

Вам не нужно перемещать мышь, чтобы получить местоположение курсора. Местоположение также сообщается о событиях, кроме указателя мыши . Вот пример клика в качестве примера:

document.body.addEventListener('click',function(e)
{
    console.log("cursor-location: " + e.clientX + ',' + e.clientY);
});
Лонни Бест
источник
1

Опираясь на ответ @ SuperNova , вот подход, использующий классы ES6, который сохраняет контекст для thisправильного обратного вызова:

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

Патрик Беркли
источник
1

Вот мое решение. Он экспортирует свойства window.currentMouseX и window.currentMouseY, которые вы можете использовать где угодно. Сначала он использует положение элемента наведения (если он есть), а затем слушает движения мыши, чтобы установить правильные значения.

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

CMS Composr Источник: https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

Салман фон Аббас
источник
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;
}
Поврежденный
источник
14
Разве это не требует от пользователя перемещения мыши?
Пол Химстра
0

Я думаю, что у меня может быть разумное решение без подсчета div и пикселей .. lol

Просто используйте кадр анимации или временной интервал функции. вам все равно понадобится событие мыши один раз, хотя только для того, чтобы инициировать, но технически вы размещаете его там, где вам когда-либо нужно.

По сути, мы всегда отслеживаем фиктивный div без движения мыши.

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

Ниже приводится логика ..

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);
}  
Джошуа
источник