Olay olmadan fare konumu nasıl elde edilir (fareyi hareket ettirmeden)?


286

Herhangi bir fare hareketi olayı olmadan (fareyi hareket ettirmeden) sayfa yüklendikten sonra JavaScript ile fare konumunu almak mümkün müdür?


61
Mousemove olayında yanlış bir şey yok. Bazı durumlarda kullanıcılar fareyi hareket ettirmez. Cevabınız için teşekkürler.
Norbert Tamas

2
@ SuperNova'nın cevabı olan Norbert Tamas (bu yıla kadar eklenmedi), fare işçisinin bunun için iyi çalıştığını gösteriyor, çünkü sayfa yükünde tetikleniyor (fare görünüm alanındaysa). 2010'da bu şekilde çalışmadı mı, yoksa hiç kimse denemeyi düşünmedi mi?
Peter Hansen

@CrescentFresh Bazı durumlarda (userscripts gibi) birçok mousemoveolay ekleyerek tarayıcıyı yavaşlatmak istemezsiniz .
Tomáš Zato - Monica'yı eski durumuna döndür

Fareyle üzerine gelindiğinde FF'de mümkündür, ancak IE ve Chrome'da yoktur.
Elad

Veya bir oyunda, kameranız oyun dünyasında hareket eder ve karakter fareye bakar (tipik yukarıdan aşağıya atıcı tarzı), ancak kullanıcı bir fareyi hareket ettirmezse, sadece fareye güveniyorsun. Ancak, bu büyük bir mesele değil, sadece işaretçinin "dünya" koordinatlarını saklıyoruz ve insanların bunu sorgulamasına izin veriyoruz.
kamranicus

Yanıtlar:


336

Gerçek cevap: Hayır, bu mümkün değil.

Tamam, sadece bir yol düşündüm. Sayfanızın tamamını, belgenin tamamını kapsayan bir div ile yerleştirin. Bunun içinde , her biri 1 piksel boyutunda 2.000 x 2.000 <a>öğe oluşturun ( :hoversözde sınıf IE 6'da çalışacaktır, bkz.). Bir özelliği değiştiren öğeler :hoveriçin bir CSS kuralı oluşturun <a>(diyelim font-family). Yük işleyicinizde, vurgulu yazı tipini bulana kadar / bulana kadar 4 milyon <a>öğenin her birinde dolaşın. Belgede koordinatları elde etmek için bu öğeden geri çekin.currentStylegetComputedStyle()

DİKKAT BU YAPMAYIN .


92
ha ha - bir noktada google'ı gezmeli ve bunu gerçekten kaç kişinin uyguladığını anlayabiliyor musunuz
Pointy

6
Aslında, çok fazla CPU yüküne gerek kalmadan uygulanabilir (sanırım. Test etmedim). Dom ready'da <a> öğelerini javascript ile derleyin, fare konumunu alın ve sonra tüm <a> öğelerini kaldırın. Fare üzerinde fare konumunu almak için başka bir işleve sahip olmalısınız. Her neyse, bu çok komikti.
machineaddict

21
Belki bu ikili arama ile pratik yapılabilir? Her seferinde <a>verilen dikdörtgenleri kapsayan bir çift eleman yaparak (boyutlandırılmış <img>elemanların mutlak konumlandırmasını kullanarak ) her seferinde dikdörtgenleri daraltarak döngü yapın . Evet, çok saçma, ama bu bilgiyi ilk fareden önce alamıyor.
Darius Bacon

29
stackoverflow.com/a/8543879/27024 , fareyi ilk kez hareket edene kadar fareyle üzerine gelmediğini söylüyor. Bu, bu şemayı geçersiz kılar.
Darius Bacon

4
@DariusBacon: Bu bağlantılı cevap doğru görünmüyor: jsbin.com/utocax/3 . Yani evet, bu yaklaşım bazı durumlar için pratik olabilir.
Tim Down

121

Edit 2020: Bu artık çalışmaz. Öyle görünüyor ki, tarayıcı satıcıları bunu düzeltti. Çoğu tarayıcı kromu kullandığından, çekirdeğinde olabilir.

Eski cevap: Ayrıca mouseenter'ı bağlayabilirsiniz (fare imleci sayfanın içindeyken sayfa yeniden yüklendikten sonra bu olay tetiklenir). Bozuk kodun genişletilmesi hile yapmalıdır:

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

Ayrıca, fare imleci etkinliğinde x ve y değerlerini null değerine ayarlayabilirsiniz. Böylece kullanıcının imleçle sayfanızda olup olmadığını kontrol edebilirsiniz.


11
Bu garip görünen tek gerçekten yararlı cevap gibi görünüyor. Gerçekten de (en son Firefox, Chrome ve IE11'de) mouseenter sayfa yüklemesinde tetiklenir ve doğru koordinatları sağlar. Bu alandaki tarayıcı davranışı son birkaç yılda değişti mi?
Peter Hansen

3
Aslında "mouseenter" herhangi bir değer katmıyor gibi görünüyor. Chrome ve IE'de aşağıdaki jsfiddle ile test ettim ve fareyi dahili belgeye (sonuç paneli) yerleştirene kadar kordinatları göstermiyorlar
Mariano Desanze

1
@Proton: Farenizi sonuç paneline, sayfanın tam olarak yüklenmesinden ÖNCE sonuç panelinin alanına getirin ve daha sonra hareket etmeyin. Yüklemeden sonra sayfa hemen farenin konumunu bilir. Fare hareketi gerekmez. Dolayısıyla, sayfa yüklendiğinde ve fare belge alanının içindeyken fare merkezi de tetiklenir. OP'nin başlangıçta istediği şey buydu. Başka hiç kimse bu cevabı vermez.
SuperNova

1
Potansiyel olarak yararlı ek bir fonksiyon eklemektir mouseleavesetleri durumunda xve yhiç arkasına nullveya'undefined'
rtpax

2
chrome 68, yukarıdaki jsfiddel kullanılarak, fare, sayfanın yüklenmesi tamamlanmadan önce oluşturulan bölgeye taşınsa bile, yükte değil ilk fare hareketinde uyarı oluşur.
junvar

84

Yapabileceğiniz şey, xy imleciniz ve koordinatları , fare her hareket ettiğinde bunları güncellemek ve depolanan konumla ihtiyacınız olanı yapmak için bir aralıkta bir işlevi çağırmaktır.

Bunun dezavantajı elbette farenin çalışması için en az bir başlangıç ​​hareketinin gerekli olmasıdır. İmleç konumunu en az bir kez güncellediği sürece, tekrar hareket edip etmediğine bakılmaksızın konumunu bulabiliriz.

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

Önceki kod, imlecinizin nerede olduğunu belirten bir mesajla saniyede bir güncellenir. Umarım bu yardımcı olur.


18
Bu yazının konusunu okudunuz mu? OP bir olay kullanmadan fare koordinatlarının nasıl alınacağını sorar. Ancak yayınınız onmousemove etkinliğini kullanmanızı önerir.
Jake

53
@jake Her ne kadar OP özellikle olay dışı bir yöntem istemiş olsa da, bu yanıt buraya bir yanıt ve muhtemelen bir çözüm arayan diğerlerine yarar sağlar. Ayrıca, bildiğim kadarıyla bu cevabı kısmen konu içinde düşünürüm, bu olayları doğrudan kullanmak zorunda kalmadan herhangi bir zamanda imleç konumunu elde etmek için en iyi yöntemdir. Bununla birlikte, cevap, gerçeği belirtme ve yorumlarda nitpick'ten kaçınmak için bir yol sunma çizgisi boyunca daha fazla ifade edilebilirdi.
jpeltoniemi

2
@Pichan Bana faydası olmadı, çünkü cursorX/Yherhangi bir olay gerçekleşmeden önce bu değişkeni doldurmanın bir yolunu arıyordum .
polkovnikov.ph

çok az kullanıcı ateş fare olayları alışkanlık
SuperUberDuper

1
Dikkatli olun, fareyle üzerine gelindiğinde bir dinleyici bulundurmak pahalıya mal olabilir. Dinleyiciyi aralıklarla yeniden oluşturmanızı ve koordinatları aldıktan sonra dinleyiciyi yok etmenizi öneririm.
KRB

10

Tim Down'ın önerdiğine benzer bir şey deneyebilirsiniz - ancak ekrandaki her piksel için öğelere sahip olmak yerine, yalnızca 2-4 öğe (kutu) oluşturun ve ekrandaki olası yerleri bölmek için konumlarını, genişliklerini, yüksekliklerini dinamik olarak değiştirin. 2-4 özyinelemeyle, böylece farenin gerçek konumunu hızlı bir şekilde bulur.

Örneğin - ilk elemanlar ekranın sağ ve sol yarısını, daha sonra üst ve alt yarıyı alır. Şimdiye kadar, farenin hangi çeyreğinde bulunduğunu zaten biliyoruz, tekrarlayabiliyoruz - bu alanın hangi çeyreğini keşfedin ...


9

@Tim Down'ın cevabı, 2.000 x 2.000 <a>öğe oluşturursanız gerçekleşmez:

Tamam, sadece bir yol düşündüm. Sayfanızın tamamını, belgenin tamamını kapsayan bir div ile yerleştirin. Bunun içinde, her biri 1 piksel boyutunda, 2.000 x 2.000 öğe oluşturun (diyelim: vurgulu sözde sınıf IE 6'da çalışacaktır, bkz.). Bir özelliği değiştiren öğeler için bir CSS: fareyle üzerine gelme kuralı oluşturun (diyelim ki font ailesi). Yük işleyicinizde, vurgulu yazı tipini bulana kadar currentStyle / getComputedStyle () öğesini kontrol ederek 4 milyon öğenin her birinde dolaşın. Belgede koordinatları elde etmek için bu öğeden geri çekin.

DİKKAT BU YAPMAYIN.

Ancak aynı anda 4 milyon öğe oluşturmak zorunda değilsiniz, bunun yerine ikili arama kullanın. Bunun <a>yerine 4 element kullanın:

  • 1. Adım: Tüm ekranı başlangıç ​​arama alanı olarak düşünün
  • Adım 2: Arama alanını 2 x 2 = 4 dikdörtgene bölün <a> öğeye
  • Adım 3: getComputedStyle()Fonksiyonu kullanarak hangi farenin hangi fareyle üzerine geldiğini belirleyin
  • Adım 4: Arama alanını bu dikdörtgene azaltın ve 2. adımdan itibaren tekrarlayın.

Bu şekilde, ekranınızın 2048 pikselden daha geniş olmadığı düşünülürse, bu adımları en fazla 11 kez tekrarlamanız gerekir.

Böylece maksimum 11 x 4 = 44 <a>eleman üreteceksiniz .

Fare konumunu tam olarak bir piksele ayarlamanız gerekmiyorsa, ancak 10 piksel hassasiyetin iyi olduğunu söyleyin. Adımları en fazla 8 kez tekrarlarsınız, bu nedenle maksimum 8 x 4 = 32 <a>eleman çizmeniz gerekir .

Ayrıca <a>, DOM genellikle yavaş olduğundan elemanları oluşturmak ve sonra yok etmek de işe yaramaz. Bunun yerine, sadece ilk 4 yeniden kullanabilirsiniz <a>elemanları ve sadece ayarlamak onların top, left, widthveheight adımlarda senin kadar döngü.

Şimdi, 4 oluşturmak <a>da aşırıya kaçıyor. Bunun yerine, her bir dikdörtgeni <a>test ederken aynı öğeyi yeniden kullanabilirsiniz getComputedStyle(). Bu nedenle, arama alanını 2 x 2 <a>öğeye bölmek yerine, tek bir <a>öğeyi topve leftstil özellikleriyle taşıyarak yeniden kullanın .

Yani, tek ihtiyacınız olan tek bir <a>eleman widthve heightmaksimum 11 kez değiştirmek ve onun topve leftmaksimum 44 kez değiştirmek ve tam fare pozisyonuna sahip olacaksınız.


3

En basit çözüm ancak% 100 doğru değil

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

Sonuç: Sonuç , kullanıcı sekmeyi değiştirdiğinde en {top: 148, left: 62.5}
yakın öğe boyutuna ve geri dönüşüne bağlıdırundefined


Benim için, undefinedne olursa olsun geri döner . Bunu nasıl kullanacağınızı açıklayabilir misiniz?
tresf

undefinedİmleç herhangi bir öğenin üzerine gelmediğinde (veya tarayıcı odağı kaybettiğinde) dönecektir . Konsoldan test yapıyorsanız bir zaman aralığı ayarlamanız gerekebilir ..
StefansArya

Teşekkürler. setTimeoutçalıştı. Ben jsfiddle kullanıyordum ve haklısın, asla bir hover olayına çarpmadı çünkü play'i her tıkladığında DOM'u yeniden çiziyor. Bu ipucunu başkaları için eklemenizi tavsiye ederim.
tresf

Ben doğru fare pozisyonu istemiyorum ama sadece fare olay nesne olmadan aşırı sağ ya da aşırı sol olduğunu bilmek istiyorum böylece çözüm benim durumumda çalışır .. teşekkür ederim
Swap-IOS-Android

2

Belki bir zamanlayıcılı bir üst sayfanız olduğunu ve belirli bir süre veya bir görev tamamlandıktan sonra kullanıcıyı yeni bir sayfaya yönlendirdiğinizi düşünüyorum. Şimdi imlecin konumunu istiyorsunuz ve bekledikleri için fareye dokunmaları gerekmiyor. Standart olayları kullanarak üst sayfadaki fareyi izleyin ve son değeri bir get veya post değişkeninde yeni sayfaya iletin.

JHarding'in kodunu ana sayfanızda kullanabilirsiniz, böylece en son konum her zaman global bir değişkende kullanılabilir:

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

Bu, bu sayfaya ana sayfanız dışındaki yollarla giden kullanıcılara yardımcı olmaz.


1

Tim Down'ın fikri gibi yatay / dikey bir arama gerçekleştirdim (önce yatay olarak düzenlenmiş dikey çizgi bağlantılarıyla dolu bir div yapın, sonra dikey olarak düzenlenmiş yatay çizgi bağlantılarıyla dolu bir div yapın ve basitçe hangisinin üzerine gelindiğini görün) ve oldukça hızlı çalışıyor. Ne yazık ki, KDE üzerinde Chrome 32 üzerinde çalışmıyor.

jsfiddle.net/5XzeE/4/


görünüşe göre kullanıcı tarafından açıkça bir fare hareketi olmadığı sürece bu hileler artık çalışmaz. :(
trusktr

1

İmlecin yerini almak için fareyi hareket ettirmeniz gerekmez . Konum, fareyle üzerine gelme dışındaki olaylarda da bildirilir . İşte bu tıklama olay bir örnek olarak:

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

1

@ SuperNova'nın cevabına dayanarak , ES6 sınıflarını kullanarak thisgeri aramalarınızda bağlamı doğru tutan bir yaklaşım :

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

İşte benim çözümüm. Her yerde kullanabileceğiniz window.currentMouseX ve window.currentMouseY özelliklerini dışa aktarır . Vurgulu bir öğenin (varsa) konumunu başlangıçta kullanır ve daha sonra doğru değerleri ayarlamak için fare hareketlerini dinler.

(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 Kaynağı: 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
Bu hala kullanıcının fareyi hareket ettirmesini gerektirmez mi?
Paul Hiemstra

0

Ben div ve piksel sayma dışında makul bir çözüm olabilir düşünüyorum .. lol

Sadece animasyon karesini veya bir fonksiyonun zaman aralığını kullanın. sadece başlatmak için yine de bir kez bir fare etkinliğine ihtiyacınız olacak, ancak teknik olarak bunu istediğiniz yere konumlandırıyorsunuz.

Aslında fare hareketi olmadan her zaman kukla bir div izliyoruz.

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

Aşağıda mantık ..

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);
}  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.