Làm thế nào để có được vị trí chuột mà không có sự kiện (không di chuyển chuột)?


286

Có thể lấy vị trí chuột bằng JavaScript sau khi tải trang mà không có bất kỳ sự kiện di chuyển chuột nào (không di chuyển chuột) không?


61
Không có gì sai với sự kiện mousemove. Chỉ trong một số trường hợp, người dùng không di chuyển chuột. Cảm ơn câu trả lời của bạn.
Norbert Tamas

2
Câu trả lời của Norbert Tamas, @ SuperNova (không được thêm vào cho đến năm nay) cho thấy mouseenter hoạt động tốt vì điều này kích hoạt tải trang (nếu chuột ở chế độ xem). Nó không hoạt động theo cách đó vào năm 2010, hay chỉ là không ai nghĩ sẽ thử nó?
Peter Hansen

@CrescentFresh Trong một số trường hợp (như usercripts), bạn không muốn làm chậm trình duyệt bằng cách thêm nhiều mousemovesự kiện.
Tomáš Zato - Tái lập Monica

Có thể trong FF khi di chuột, nhưng không có trong IE và Chrome.
Elad

Hoặc, trong một trò chơi, máy ảnh của bạn di chuyển xung quanh thế giới trò chơi và nhân vật đang nhìn vào con chuột (kiểu bắn súng từ trên xuống điển hình) nhưng nếu người dùng không di chuyển chuột, nó sẽ xoay quanh điểm sai khi bạn di chuyển xung quanh nếu bạn chỉ dựa vào mousemove. Tuy nhiên, đó không phải là vấn đề lớn, chúng tôi chỉ lưu trữ các "thế giới" của con trỏ và để mọi người truy vấn điều đó.
kamranicus

Câu trả lời:


336

Câu trả lời thực sự: Không, điều đó là không thể.

OK, tôi vừa nghĩ ra một cách. Xếp chồng trang của bạn với một div bao trùm toàn bộ tài liệu. Bên trong đó, tạo (giả sử) 2.000 x 2.000 <a>phần tử (để lớp :hovergiả sẽ hoạt động trong IE 6, xem), mỗi kích thước 1 pixel. Tạo :hoverquy tắc CSS cho những <a>yếu tố thay đổi thuộc tính (giả sử font-family). Trong trình xử lý tải của bạn, xoay vòng qua từng trong số 4 triệu <a>phần tử, kiểm tra currentStyle/ getComputedStyle()cho đến khi bạn tìm thấy phần tử có phông chữ di chuột. Ngoại suy trở lại từ phần tử này để có được tọa độ trong tài liệu.

NB KHÔNG LÀM NÀY .


92
ha ha - tại một số điểm bạn nên google xung quanh và xem liệu bạn có thể biết được có bao nhiêu người đã thực hiện việc này không
Pointy

6
Trên thực tế, nó có thể thực hiện được mà không phải tải CPU nhiều (tôi nghĩ. Tôi chưa thử nghiệm nó). Trên dom sẵn sàng xây dựng các phần tử <a> bằng javascript, lấy tư thế chuột và sau đó xóa tất cả các phần tử <a>. Trên mousemouse bạn nên có chức năng khác để lấy vị trí chuột. Dù sao, điều này là vui nhộn.
máy móc

21
Có lẽ điều này có thể được thực hiện với tìm kiếm nhị phân? Vòng lặp tạo một cặp <a>phần tử bao phủ các hình chữ nhật đã cho (sử dụng định vị tuyệt đối các <img>phần tử có kích thước , tôi cho rằng), thu nhỏ hình chữ nhật mỗi lần. Vâng, thật nực cười, nhưng vì vậy không thể có được thông tin này trước mousemove đầu tiên.
Darius Bacon

29
stackoverflow.com/a/8543879/27024 nói rằng di chuột không kích hoạt cho đến khi chuột di chuyển lần đầu tiên. Điều này cho phép chương trình này.
Darius Bacon

4
@DariusBacon: Câu trả lời được liên kết đó dường như không chính xác: jsbin.com/utocax/3 . Vì vậy, có, cách tiếp cận này có thể là thực tế cho một số tình huống.
Tim Down

121

Chỉnh sửa 2020: Điều này không hoạt động nữa. Có vẻ như vậy, các nhà cung cấp trình duyệt đã vá điều này. Bởi vì hầu hết các trình duyệt đều dựa vào crom, nên nó có thể nằm trong lõi của nó.

Câu trả lời cũ: Bạn cũng có thể hook mouseenter (sự kiện này được kích hoạt sau khi tải lại trang, khi người quản lý ở trong trang). Mở rộng mã bị hỏng nên thực hiện thủ thuật:

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

Bạn cũng có thể đặt x và y thành null trên sự kiện mouseleave. Vì vậy, bạn có thể kiểm tra xem người dùng có ở trên trang của mình bằng con trỏ không.


11
Đây dường như là câu trả lời thực sự hữu ích duy nhất ở đây, có vẻ kỳ quặc. Thật vậy (trong Firefox, Chrome và IE11 mới nhất), mouseenter kích hoạt tải trang và cung cấp tọa độ chính xác. Có hành vi trình duyệt trong lĩnh vực này chỉ đơn giản là thay đổi trong vài năm qua?
Peter Hansen

3
Trong thực tế, "mouseenter" dường như không thêm bất kỳ giá trị nào. Tôi đã thử nghiệm với jsfiddle sau trong Chrome và IE và chúng không hiển thị các dây cho đến khi bạn đặt chuột vào tài liệu bên trong (bảng kết quả): jsfiddle.net/xkpd784o/1
Mariano Desanze

1
@Proton: Di chuyển chuột của bạn đến bảng kết quả đến khu vực của trang kết quả TRƯỚC đã tải đầy đủ và không di chuyển hơn. Sau khi tải trang, ngay lập tức biết vị trí của chuột. Không cần di chuyển chuột. Vì vậy, mouseenter cũng được kích hoạt, khi trang đã được tải và chuột nằm trong vùng tài liệu. Đó là, những gì OP ban đầu muốn. Không ai khác cung cấp câu trả lời này.
SuperNova

1
Một bổ sung có khả năng hữu ích là thêm một chức năng cho mouseleavesự kiện đặt xyquay lại nullhoặc'undefined'
rtpax

2
chrome 68, sử dụng jsfiddel ở trên, cảnh báo xảy ra khi di chuyển chuột đầu tiên và không tải, ngay cả khi chuột được di chuyển đến vùng được hiển thị trước khi tải xong trang.
Junvar

84

Những gì bạn có thể làm là tạo các biến cho xytọa độ của con trỏ, cập nhật chúng bất cứ khi nào chuột di chuyển và gọi một hàm trên một khoảng để làm những gì bạn cần với vị trí được lưu trữ.

Nhược điểm của điều này tất nhiên là ít nhất một chuyển động ban đầu của chuột là cần thiết để nó hoạt động. Miễn là con trỏ cập nhật vị trí của nó ít nhất một lần, chúng ta có thể tìm thấy vị trí của nó bất kể nó có di chuyển nữa hay không.

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

Mã trước cập nhật mỗi giây một lần với thông báo vị trí con trỏ của bạn. Tôi hi vọng cái này giúp được.


18
Bạn đã đọc chủ đề của bài này? OP hỏi làm thế nào để có được tọa độ chuột mà không cần sử dụng một sự kiện. Tuy nhiên, bài viết của bạn đề nghị sử dụng sự kiện onmousemove.
jake

53
@jake Mặc dù OP đặc biệt yêu cầu một phương pháp không phải sự kiện, câu trả lời này mang lại lợi ích cho những người khác đến đây để tìm câu trả lời và có thể là một cách giải quyết. Ngoài ra, tôi sẽ xem xét câu trả lời này một phần trong chủ đề vì theo như tôi biết, đây là phương pháp tốt nhất để có được vị trí con trỏ tại bất kỳ thời điểm nào mà không phải sử dụng trực tiếp các sự kiện. Điều đó nói rằng, câu trả lời có thể được diễn đạt nhiều hơn dọc theo dòng tuyên bố thực tế và đưa ra một cách để tránh gây nhầm lẫn trong các bình luận.
jpeltoniemi

2
@Pichan Nó không có lợi cho tôi, vì tôi đã tìm cách để điền vào các cursorX/Ybiến đó trước khi bất kỳ sự kiện nào xảy ra.
polkovnikov.ph

Rất ít người dùng không kích hoạt các sự kiện chuột
SuperUberDuper

1
Cẩn thận, có thể tốn kém để giữ một người nghe mousemove xung quanh. Tôi sẽ đề nghị tái tạo người nghe trong khoảng và phá hủy người nghe sau khi bạn có tọa độ.
KRB

10

Bạn có thể thử một cái gì đó tương tự như những gì Tim Down đề xuất - nhưng thay vì có các yếu tố cho mỗi pixel trên màn hình, hãy tạo chỉ 2-4 phần tử (hộp) và thay đổi vị trí, chiều rộng, chiều cao của chúng một cách linh hoạt để phân chia các vị trí có thể có trên màn hình bằng 2-4 đệ quy, do đó tìm thấy vị trí thực của chuột một cách nhanh chóng.

Ví dụ: các phần tử đầu tiên chiếm nửa bên phải và bên trái của màn hình, sau đó là nửa trên và nửa dưới. Đến bây giờ chúng ta đã biết chuột nằm ở vị trí nào, có thể lặp lại - khám phá xem phần tư của không gian này ...


9

Câu trả lời của @Tim Down không hiệu quả nếu bạn kết xuất 2.000 x 2.000 <a>phần tử:

OK, tôi vừa nghĩ ra một cách. Xếp chồng trang của bạn với một div bao trùm toàn bộ tài liệu. Bên trong đó, tạo (giả sử) 2.000 x 2.000 phần tử (để lớp giả: hover sẽ hoạt động trong IE 6, xem), mỗi kích thước 1 pixel. Tạo CSS: quy tắc di chuột cho các thành phần thay đổi thuộc tính (giả sử họ phông chữ). Trong trình xử lý tải của bạn, xoay vòng qua từng trong số 4 triệu phần tử, kiểm tra currentStyle / getComputingStyle () cho đến khi bạn tìm thấy phần tử có phông chữ di chuột. Ngoại suy trở lại từ phần tử này để có được tọa độ trong tài liệu.

NB KHÔNG LÀM NÀY.

Nhưng bạn không phải kết xuất 4 triệu phần tử cùng một lúc, thay vào đó hãy sử dụng tìm kiếm nhị phân. Chỉ cần sử dụng 4 <a>yếu tố thay thế:

  • Bước 1: Coi toàn bộ màn hình là khu vực tìm kiếm bắt đầu
  • Bước 2: Chia vùng tìm kiếm thành 2 x 2 = 4 <a>phần tử hình chữ nhật
  • Bước 3: Sử dụng getComputedStyle()chức năng xác định trong đó chuột hình chữ nhật
  • Bước 4: Thu nhỏ vùng tìm kiếm vào hình chữ nhật đó và lặp lại từ bước 2.

Bằng cách này, bạn sẽ cần lặp lại các bước này tối đa 11 lần, vì màn hình của bạn không rộng hơn 2048px.

Vì vậy, bạn sẽ tạo tối đa 11 x 4 = 44 <a>phần tử.

Nếu bạn không cần xác định chính xác vị trí chuột với pixel, nhưng nói chính xác 10px là ổn. Bạn sẽ lặp lại các bước tối đa 8 lần, vì vậy bạn sẽ cần vẽ tối đa 8 x 4 = 32 <a>phần tử.

Ngoài ra, việc tạo và hủy các <a>phần tử không được thực hiện vì DOM thường chậm. Thay vào đó, bạn chỉ có thể tái sử dụng 4 ban đầu <a>yếu tố và chỉ cần điều chỉnh của họ top, left, widthheightnhư bạn vòng qua các bước.

Bây giờ, tạo 4 <a>là một quá mức cần thiết là tốt. Thay vào đó, bạn có thể sử dụng lại cùng một <a>yếu tố khi kiểm tra getComputedStyle()trong mỗi hình chữ nhật. Vì vậy, thay vì chia vùng tìm kiếm thành 2 x 2 <a>phần tử, chỉ cần sử dụng lại một <a>phần tử bằng cách di chuyển nó với các thuộc tính topleftkiểu.

Vì vậy, tất cả những gì bạn cần là một <a>yếu tố duy nhất thay đổi widthheighttối đa 11 lần, và thay đổi tối đa toplefttối đa 44 lần và bạn sẽ có vị trí chuột chính xác.


3

Giải pháp đơn giản nhất nhưng không chính xác 100%.

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

Kết quả: {top: 148, left: 62.5}
Kết quả phụ thuộc vào kích thước phần tử gần nhất và trả về undefinedkhi người dùng chuyển tab


Đối với tôi, nó trả lại undefinedbất kể. Bạn có thể xây dựng như thế nào để sử dụng này?
tresf

Nó sẽ trở lại undefinedkhi con trỏ không di chuột vào bất kỳ phần tử nào (hoặc khi trình duyệt mất tiêu điểm). Bạn có thể cần đặt khoảng thời gian nếu bạn đang thử nghiệm từ bảng điều khiển ..
StefansArya

Cảm ơn. setTimeoutđã làm việc. Tôi đã sử dụng jsfiddle và bạn nói đúng, nó không bao giờ gặp sự kiện di chuột vì nó vẽ lại DOM mỗi khi bạn nhấp vào chơi. Tôi sẽ khuyên bạn nên thêm gợi ý này cho người khác.
tresf

Tôi không muốn vị trí chuột chính xác nhưng tôi chỉ muốn biết rằng chuột cực kỳ phải hoặc cực trái vào chức năng mà không có đối tượng sự kiện để giải pháp của bạn hoạt động trong trường hợp của tôi..cảm ơn bạn
Swap-IOS-Android

2

Tôi hình dung rằng có thể bạn có một trang mẹ có bộ đếm thời gian và sau một khoảng thời gian nhất định hoặc một nhiệm vụ được hoàn thành, bạn chuyển tiếp người dùng đến một trang mới. Bây giờ bạn muốn vị trí con trỏ và vì chúng đang chờ nên chúng không nhất thiết phải chạm vào chuột. Vì vậy, theo dõi chuột trên trang mẹ bằng các sự kiện tiêu chuẩn và chuyển giá trị cuối cùng sang trang mới trong một biến hoặc một biến bài.

Bạn có thể sử dụng mã của JHending trên trang mẹ của mình để vị trí mới nhất luôn có sẵn trong một biến toàn cục:

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

Điều này sẽ không giúp người dùng điều hướng đến trang này bằng các phương tiện khác ngoài trang chính của bạn.


1

Tôi đã triển khai tìm kiếm theo chiều ngang / dọc, (đầu tiên tạo một div đầy đủ các liên kết đường dọc được sắp xếp theo chiều ngang, sau đó tạo một div đầy đủ các liên kết đường ngang được sắp xếp theo chiều dọc và chỉ cần xem cái nào có trạng thái di chuột) như ý tưởng của Tim Down ở trên và nó hoạt động khá nhanh. Đáng buồn thay, không hoạt động trên Chrome 32 trên KDE.

jsfiddle.net/5XzeE / 4 /


rõ ràng các thủ thuật này không còn hoạt động trừ khi người dùng di chuyển chuột rõ ràng. :(
trusktr

1

Bạn không phải di chuyển chuột để lấy vị trí của con trỏ. Địa điểm cũng được báo cáo về các sự kiện khác ngoài mousemove . Đây là một sự kiện nhấp chuột làm ví dụ:

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

1

Riffing trên câu trả lời của @ SuperNova , đây là một cách tiếp cận sử dụng các lớp ES6 để giữ ngữ cảnh thischính xác trong cuộc gọi lại của bạn:

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

Đây là giải pháp của tôi. Nó xuất khẩu window.currentMouseXwindow.currentMouseY tài sản mà bạn có thể sử dụng bất cứ nơi nào. Nó sử dụng vị trí của một phần tử lơ lửng (nếu có) ban đầu và sau đó lắng nghe chuyển động của chuột để đặt các giá trị chính xác.

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

Nguồn Composr CMS : https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R120


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
Điều này vẫn không yêu cầu người dùng di chuyển chuột?
Paul Hiemstra

0

Tôi nghĩ rằng tôi có thể có một giải pháp hợp lý với việc đếm div và pixel..lol

Đơn giản chỉ cần sử dụng khung hình động hoặc một khoảng thời gian của một chức năng. bạn vẫn sẽ cần một sự kiện chuột một lần mặc dù chỉ để bắt đầu, nhưng về mặt kỹ thuật bạn định vị nó ở bất cứ đâu bạn muốn.

Về cơ bản, chúng tôi đang theo dõi một div giả mọi lúc với chuyển động của chuột.

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

Dưới đây là logic ..

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);
}  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.