JavaScript: Kiểm tra nếu nút chuột xuống?


136

Có cách nào để phát hiện nếu nút chuột hiện đang bị tắt trong JavaScript không?

Tôi biết về sự kiện "mousedown", nhưng đó không phải là điều tôi cần. Đôi khi SAU nút chuột được nhấn, tôi muốn có thể phát hiện nếu nó vẫn được nhấn xuống.

Điều này có thể không?


14
Tại sao bạn chấp nhận Câu trả lời không trả lời câu hỏi của bạn. Đăng ký mousedown và mouseup là sai (vì bạn có thể di chuột ra ngoài trình duyệt và để nó nghĩ rằng bạn vẫn đang kéo). Đến sau vấn đề của bạn và đến trang này là hoàn toàn vô dụng
Jack

@Jack nó trả lời câu hỏi của tôi. Xin vui lòng đọc câu hỏi của tôi và sau đó đọc câu trả lời. Rõ ràng hơn 100 người khác đồng ý rằng đó là một câu trả lời tốt.
TM.

4
vâng .. nhưng tôi, alfred và 8 người khác đang nói với bạn rằng theo dõi mouseup và mousedown không phải là cách đúng đắn. Câu trả lời đúng sẽ liên quan đến việc phân tích đối tượng sự kiện trong trình xử lý mà bạn chọn hoặc phân tích tất cả các sự kiện liên quan đến chuột (như nhập / thoát) nếu bạn cần kiểm tra theo thời gian thay vì kiểm tra theo sự kiện.
Jack

Câu hỏi này đã được hỏi và trả lời hơn 7 năm trước. Tôi không nhận được thông báo khi có câu trả lời mới (nhưng tôi cho ý kiến). Viết một câu trả lời tốt hơn và cộng đồng sẽ nâng nó lên hàng đầu :) Rất nhiều thông tin trở nên cũ kỹ và mọi thứ thay đổi.
TM.

2
@TM. Xin lỗi để necro, nhưng ... Không, thông tin đó sẽ không bao giờ được đưa lên đầu. Một người không tự trả lời, một khi được chấp nhận, sẽ ở trên đỉnh mãi mãi. Ngoài ra, "oh rất nhiều người đã bình chọn cho cái này" không có nghĩa là câu trả lời là một câu hỏi hay; nó chỉ có nghĩa là nhiều người đã nhìn thấy nó, nghĩ rằng nó trông ổn, và nhấn vào upvote bởi vì nó dường như làm việc cho họ.
Vụ kiện của Quỹ Monica

Câu trả lời:


147

Về giải pháp của Pax: nó không hoạt động nếu người dùng nhấp nhiều hơn một nút cố ý hoặc vô tình. Đừng hỏi tôi làm sao tôi biết :-(.

Mã chính xác phải như thế:

var mouseDown = 0;
document.body.onmousedown = function() { 
  ++mouseDown;
}
document.body.onmouseup = function() {
  --mouseDown;
}

Với bài kiểm tra như thế này:

if(mouseDown){
  // crikey! isn't she a beauty?
}

Nếu bạn muốn biết nút nào được nhấn, hãy chuẩn bị để tạo chuộtDown một mảng các bộ đếm và đếm riêng cho các nút riêng biệt:

// let's pretend that a mouse doesn't have more than 9 buttons
var mouseDown = [0, 0, 0, 0, 0, 0, 0, 0, 0],
    mouseDownCount = 0;
document.body.onmousedown = function(evt) { 
  ++mouseDown[evt.button];
  ++mouseDownCount;
}
document.body.onmouseup = function(evt) {
  --mouseDown[evt.button];
  --mouseDownCount;
}

Bây giờ bạn có thể kiểm tra những nút nào được nhấn chính xác:

if(mouseDownCount){
  // alright, let's lift the little bugger up!
  for(var i = 0; i < mouseDown.length; ++i){
    if(mouseDown[i]){
      // we found it right there!
    }
  }
}

Bây giờ được cảnh báo rằng mã ở trên sẽ chỉ hoạt động đối với các trình duyệt tuân thủ tiêu chuẩn cho bạn số nút bắt đầu từ 0 trở lên. IE sử dụng một mặt nạ bit của các nút hiện đang nhấn:

  • 0 cho "không có gì được nhấn"
  • 1 cho trái
  • 2 cho đúng
  • 4 cho giữa
  • và bất kỳ kết hợp nào ở trên, ví dụ: 5 cho trái + giữa

Vì vậy, điều chỉnh mã của bạn cho phù hợp! Tôi để nó như một bài tập.

Và hãy nhớ rằng: IE sử dụng một đối tượng sự kiện toàn cầu có tên là "sự kiện".

Ngẫu nhiên IE có một tính năng hữu ích trong trường hợp của bạn: khi các trình duyệt khác chỉ gửi "nút" cho các sự kiện nút chuột (onclick, onmousedown và onmouseup), IE cũng gửi nó với onmousemove. Vì vậy, bạn có thể bắt đầu nghe onmousemove khi bạn cần biết trạng thái nút và kiểm tra evt.button ngay khi bạn nhận được nó - bây giờ bạn biết nút chuột nào được nhấn:

// for IE only!
document.body.onmousemove = function(){
  if(event.button){
    // aha! we caught a feisty little sheila!
  }
};

Tất nhiên bạn chẳng nhận được gì nếu cô ấy chơi chết và không di chuyển.

Các liên kết có liên quan:

Cập nhật # 1 : Tôi không biết lý do tại sao tôi mang theo tài liệu. Kiểu mã của mọi người. Sẽ tốt hơn nếu đính kèm xử lý sự kiện trực tiếp vào tài liệu.


1
Sau khi thử nghiệm, có vẻ như evt.button thực tế không tồn tại onmousemove với IE7 ...
TM.

5
Tôi nghĩ rằng điều này sẽ không hoạt động trong Chrome, bởi vì Chrome không tạo ra các sự kiện mouseup nếu sự sắp xếp ban đầu xảy ra trên thanh cuộn. Một ví dụ , từ vấn đề Chrome / Chromium này . Vì vậy, nút chuột trái của bạn sẽ bị hỏng mãi mãi, nếu có một thanh cuộn mà ai đó sử dụng! (Trong Chrome)
KajMagnus

1
Tôi thích giải pháp của bạn, nhưng điều gì sẽ xảy ra nếu con chuột đến từ một ứng dụng khác nói từ ms và nó kéo một số văn bản. Làm thế nào bạn sẽ phát hiện ra rằng con chuột đang xuống?
Shadrack B. Orina

6
Tôi không hiểu tại sao bạn lại tăng các mảng mousedown trong ví dụ thứ hai. Tại sao một bộ đếm cho mỗi nút chứ không phải là một bool cho mỗi nút?
amwinter

2
Đây là một câu hỏi thực sự phổ biến (và câu trả lời). Tôi ngạc nhiên khi điều này chưa xuất hiện, nhưng bạn không cần lưu trữ dữ liệu chuột. Bạn chỉ có thể cắm event.buttonsvào bất kỳ trình kích hoạt sự kiện nào mà bạn đang sử dụng mà không cần các biến được lưu bên ngoài. Tôi đã hỏi một câu hỏi hoàn toàn mới (vì sự kiện mouseup của tôi không phải lúc nào cũng kích hoạt, vì vậy giải pháp này không hiệu quả với tôi) và nhận được câu trả lời đó trong khoảng 5 phút.
RoboticRenaissance

32

Đây là một câu hỏi cũ và các câu trả lời ở đây dường như chủ yếu là ủng hộ việc sử dụng mousedownmouseupđể theo dõi xem một nút có được nhấn hay không. Nhưng như những người khác đã chỉ ra, mouseupsẽ chỉ kích hoạt khi được thực hiện trong trình duyệt, điều này có thể dẫn đến mất dấu trạng thái nút.

Tuy nhiên, MouseEvent (bây giờ) cho biết nút nào hiện đang được đẩy:

  • Đối với tất cả các trình duyệt hiện đại (trừ Safari), hãy sử dụng MouseEvent.buttons
  • Đối với Safari, sử dụng MouseEvent.which( buttonssẽ không được xác định cho Safari) Lưu ý: whichsử dụng các số khác nhau từ buttonscác nhấp chuột phải và giữa.

Khi được đăng ký document, mousemovesẽ kích hoạt ngay khi con trỏ bật lại trình duyệt, vì vậy nếu người dùng phát hành bên ngoài thì trạng thái sẽ được cập nhật ngay khi họ quay lại bên trong.

Một triển khai đơn giản có thể trông giống như:

var leftMouseButtonOnlyDown = false;

function setLeftButtonState(e) {
  leftMouseButtonOnlyDown = e.buttons === undefined 
    ? e.which === 1 
    : e.buttons === 1;
}

document.body.onmousedown = setLeftButtonState;
document.body.onmousemove = setLeftButtonState;
document.body.onmouseup = setLeftButtonState;

Nếu các kịch bản phức tạp hơn được yêu cầu (các nút khác nhau / nhiều nút / phím điều khiển), hãy xem tài liệu của MouseEvent. Khi / nếu Safari nâng trò chơi của mình, việc này sẽ trở nên dễ dàng hơn.


6
Mã này kiểm tra nếu CHỈ nhấn nút chính và yêu cầu tất cả các nút khác không được nhấn. (ví dụ: nếu cả hai chính và phụ được nhấn, e.buttonssẽ là sai 1+2=3, vì vậy e.buttons === 1sẽ là sai). Nếu bạn muốn kiểm tra xem nút chính có bị hỏng không, nhưng đừng quan tâm đến bất kỳ trạng thái nút nào khác, hãy làm điều này:(e.buttons & 1) === 1
AJ Richardson

Tôi có một tình huống mà tôi mong đợi rằng trong một lần chạm chuột, tôi sẽ nhận được mã nút là '1' nhưng nó tạo ra '7', - tất cả công việc đều có trên Chrome. Ai đó có ý kiến ​​gì không?
Hội trường Vasily

@VasilyHall Nhìn vào các tài liệu MDN MouseEvent.buttons, có vẻ như điều đó 7có nghĩa là nó nghĩ rằng các nút Chính, Phụ và Phụ đều được nhấn cùng nhau. Tôi không chắc tại sao lại như vậy - bạn có đang sử dụng chuột cao cấp không? Nếu vậy, có lẽ nó đáng để thử với một cái cơ bản. Nếu bạn chỉ cần làm cho nó hoạt động, bạn có thể sử dụng kiểm tra bitwise để đảm bảo rằng nút bên trái được nhấn và bỏ qua bất kỳ người nào khác. ví dụ. MouseEvent.buttons & 1 === 1.
Jono Job

Cảm ơn bạn, tôi đã sử dụng JavaScript của mình bên trong một trình duyệt đặc biệt: Chrome nhúng (ium?) Trong ứng dụng Adobe Illustrator - Tôi cá là sự kết hợp của tất cả những thứ khác nhau dẫn đến 7, mặc dù chỉ cần nhấn một nút . Xem làm thế nào điều này phù hợp trong ứng dụng của tôi, tôi chỉ đơn giản là kiểm tra 1 hoặc 7 để tạo thuận lợi cho khả năng tương tác của tôi. Tôi sẽ thêm, mặc dù tôi sử dụng chuột trackball Logitech M570 (hoặc bất cứ thứ gì), nó đăng ký chính xác 1 trong trình duyệt thông thường nhưng 7 bên trong Illustrator.
Hội trường Vasily

16

Tôi nghĩ cách tiếp cận tốt nhất cho việc này là giữ bản ghi trạng thái nút chuột của riêng bạn, như sau:

var mouseDown = 0;
document.body.onmousedown = function() { 
    mouseDown = 1;
}
document.body.onmouseup = function() {
    mouseDown = 0;
}

và sau đó, trong mã của bạn:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}

+1 và cảm ơn. Tôi nghĩ rằng tôi có thể phải dùng đến điều này, nhưng tôi đã hy vọng có một số tính năng cho phép bạn chỉ cần kiểm tra trạng thái trực tiếp.
TM.

12
Có một lý do cho việc không sử dụng boolean?
moala

1
@moala Tôi nghĩ rằng Int dường như ít gõ hơn và hiệu suất tốt hơn một chút: jsperf.com/bool-vs-int
Johnathan Elmore

12

giải pháp không tốt người ta có thể "mousedown" trên tài liệu, sau đó "mouseup" bên ngoài trình duyệt, và trong trường hợp này, trình duyệt vẫn sẽ nghĩ rằng chuột bị hỏng.

giải pháp tốt duy nhất là sử dụng đối tượng IE.event.


11
Tôi thấy bạn đến từ đâu, nhưng có một giải pháp chỉ hoạt động cho IE cũng không phải là một giải pháp tốt.
TM.

@alfred Trong một số trường hợp, có thể giúp biết nếu mousemove ra khỏi cửa sổ. If (event.target.nodeName.toLowerCase === 'html') down = 0;
BF

6

Tôi biết đây là một bài viết cũ, nhưng tôi nghĩ rằng việc theo dõi nút chuột bằng cách sử dụng chuột lên / xuống cảm thấy hơi khó hiểu, vì vậy tôi đã tìm thấy một giải pháp thay thế có thể thu hút một số người.

<style>
    div.myDiv:active {
        cursor: default;
    }
</style>

<script>
    function handleMove( div ) {
        var style = getComputedStyle( div );
        if (style.getPropertyValue('cursor') == 'default')
        {
            // You're down and moving here!
        }
    }
</script>

<div class='myDiv' onmousemove='handleMove(this);'>Click and drag me!</div>

Bộ chọn hoạt động xử lý nhấp chuột tốt hơn nhiều so với chuột lên / xuống, bạn chỉ cần một cách đọc trạng thái đó trong sự kiện onmousemove. Vì vậy, tôi cần phải gian lận và dựa vào thực tế là con trỏ mặc định là "tự động" và tôi chỉ thay đổi nó thành "mặc định", đây là thứ mà tự động chọn theo mặc định.

Bạn có thể sử dụng bất cứ thứ gì trong đối tượng được getComputingStyle trả về mà bạn có thể sử dụng làm cờ mà không làm đảo lộn giao diện trang của bạn, ví dụ như màu viền.

Tôi muốn đặt kiểu do người dùng xác định trong phần: hoạt động, nhưng tôi không thể làm việc đó. Sẽ tốt hơn nếu có thể.


Cảm ơn đã chia sẻ điều này. Tôi đã sử dụng ý tưởng này cho logic kiểu dáng kéo thả, nhưng gặp phải một vấn đề trên IE và phải đưa vào logic bổ sung
Eyup Yusein

4

Đoạn mã sau sẽ cố gắng thực thi chức năng "doStuff" 2 giây sau khi sự kiện mouseDown xảy ra trong document.body. Nếu người dùng nhấc nút lên, sự kiện mouseUp sẽ xảy ra và hủy thực thi bị trì hoãn.

Tôi khuyên bạn nên sử dụng một số phương pháp để đính kèm sự kiện trên nhiều trình duyệt - thiết lập rõ ràng các thuộc tính mousedown và mouseup để đơn giản hóa ví dụ.

function doStuff() {
  // does something when mouse is down in body for longer than 2 seconds
}

var mousedownTimeout;

document.body.onmousedown = function() { 
  mousedownTimeout = window.setTimeout(doStuff, 2000);
}

document.body.onmouseup = function() {
  window.clearTimeout(mousedownTimeout);
}

Cảm ơn, nhưng đây không hoàn toàn là hành vi tôi đang tìm kiếm (mặc dù tôi có thể thấy câu hỏi của tôi chỉ ra rằng đây là điều tôi đang cố gắng thực hiện).
TM.

3

Ngắn và ngọt

Tôi không chắc tại sao không có câu trả lời nào trước đây có hiệu quả với tôi, nhưng tôi đã nghĩ ra giải pháp này trong một khoảnh khắc eureka. Nó không chỉ hoạt động, mà còn thanh lịch nhất:

Thêm vào thẻ cơ thể:

onmouseup="down=0;" onmousedown="down=1;"

Sau đó kiểm tra và thực hiện myfunction()nếu downbằng 1:

onmousemove="if (down==1) myfunction();"

4
bạn là người mới, vì vậy tôi sẽ giúp bạn một chút ở đây. Trước hết, hãy chú ý ngữ pháp của bạn trong bài viết của bạn - tôi có lẽ đã dành nhiều thời gian để sửa nó hơn là bạn đặt nó. Thứ hai, giải pháp của bạn chỉ là một phiên bản khác của những thứ khác được liệt kê ở trên - nó không có gì mới. Thứ ba, giải pháp của bạn sử dụng một kỹ thuật gọi là "sử dụng cờ", mà Thomas Hansen đã đề xuất ở trên. Hãy cẩn thận kiểm tra ngữ pháp của bạn và không lặp lại các giải pháp khi đăng lên các bài đăng cũ hơn mà không cung cấp một số giải thích về lý do tại sao các giải pháp khác không hiệu quả với bạn.
Zachary Kniebel

5
Tuy nhiên, tôi đã bỏ phiếu cho giải pháp của bạn, vì nó hợp lệ và bạn chưa quen với SO
Zachary Kniebel

2

Bạn có thể kết hợp @Pax và câu trả lời của tôi để có được thời lượng mà chuột đã ngừng hoạt động:

var mousedownTimeout,
    mousedown = 0;

document.body.onmousedown = function() {
  mousedown = 0; 
  window.clearInterval(mousedownTimeout);
  mousedownTimeout = window.setInterval(function() { mousedown += 200 }, 200);
}

document.body.onmouseup = function() {
  mousedown = 0;
  window.clearInterval(mousedownTimeout);
}

Sau đó:

if (mousedown >= 2000) {
  // do something if the mousebutton has been down for at least 2 seconds
}

Đó không phải là một ý tưởng tồi, Jake. Bạn có cần xóa ClearInterval () trong onmouseup () trước khi đặt mousedown thành 0 không? Tôi cảnh giác với chức năng hẹn giờ bắn giữa cài đặt thành 0 và dừng bộ hẹn giờ, để thời gian chờ ở mức 200? Tương tự như vậy trong onmousedown.
paxdiablo

Thứ tự của ClearInterval sẽ không tạo ra sự khác biệt vì luồng thực thi hiện tại sẽ kết thúc trước khi bất kỳ sự kiện nào (bao gồm cả bộ định thời) bắt đầu.
Nathaniel Reinhart

2

Bạn cần xử lý MouseDown và MouseUp và đặt một số cờ hoặc thứ gì đó để theo dõi nó "sau này trên đường" ... :(


2

Nếu bạn đang làm việc trong một trang phức tạp với các trình xử lý sự kiện chuột hiện có, tôi khuyên bạn nên xử lý sự kiện khi chụp (thay vì bong bóng). Để làm điều này, chỉ cần thiết lập các tham số thứ 3 của addEventListenerđể true.

Ngoài ra, bạn có thể muốn kiểm tra event.whichđể đảm bảo bạn xử lý tương tác người dùng thực tế chứ không phải các sự kiện chuột, vd elem.dispatchEvent(new Event('mousedown')).

var isMouseDown = false;

document.addEventListener('mousedown', function(event) { 
    if ( event.which ) isMouseDown = true;
}, true);

document.addEventListener('mouseup', function(event) { 
    if ( event.which ) isMouseDown = false;
}, true);

Thêm trình xử lý vào tài liệu (hoặc cửa sổ) thay vì document.body là điều quan trọng b / c nó đảm bảo rằng các sự kiện mouseup bên ngoài cửa sổ vẫn được ghi lại.


1

Sử dụng api MouseEvent , để kiểm tra nút nhấn, nếu có:

document.addEventListener('mousedown', (e) => console.log(e.buttons))

Trả lại :

Một số đại diện cho một hoặc nhiều nút. Đối với nhiều hơn một nút được nhấn đồng thời, các giá trị được kết hợp (ví dụ: 3 là chính + phụ).

0 : No button or un-initialized
1 : Primary button (usually the left button)
2 : Secondary button (usually the right button)
4 : Auxilary button (usually the mouse wheel button or middle button)
8 : 4th button (typically the "Browser Back" button)
16 : 5th button (typically the "Browser Forward" button)

0

Sử dụng jQuery, giải pháp sau đây xử lý ngay cả "kéo ra khỏi trang rồi phát hành trường hợp".

$(document).mousedown(function(e) {
    mouseDown = true;
}).mouseup(function(e) {
    mouseDown = false;
}).mouseleave(function(e) {
    mouseDown = false;
});

Tôi không biết làm thế nào nó xử lý nhiều nút chuột. Nếu có một cách để bắt đầu nhấp bên ngoài cửa sổ, sau đó đưa chuột vào cửa sổ, thì điều này có lẽ cũng không hoạt động đúng ở đó.


0

Bên dưới ví dụ jQuery, khi chuột lớn hơn $ ('. Element'), màu sẽ thay đổi tùy thuộc vào nút chuột nào được nhấn.

var clicableArea = {
    init: function () {
        var self = this;
        ('.element').mouseover(function (e) {
            self.handlemouseClick(e, $(this));
        }).mousedown(function (e) {
            self.handlemouseClick(e, $(this));
        });
    },
    handlemouseClick: function (e, element) {
        if (e.buttons === 1) {//left button
            element.css('background', '#f00');
        }
        if (e.buttons === 2) { //right buttom
            element.css('background', 'none');
        }
    }
};
$(document).ready(function () {
    clicableArea.init();
});

0

Như đã nói @Jack, khi mouseupxảy ra bên ngoài cửa sổ trình duyệt, chúng tôi không biết về điều đó ...

Mã này (gần như) làm việc cho tôi:

window.addEventListener('mouseup', mouseUpHandler, false);
window.addEventListener('mousedown', mouseDownHandler, false);

Thật không may, tôi sẽ không nhận được mouseupsự kiện trong một trong những trường hợp đó:

  • Người dùng đồng thời nhấn phím bàn phím và nút chuột, nhả nút chuột bên ngoài cửa sổ trình duyệt rồi nhả phím.
  • Người dùng nhấn đồng thời hai nút chuột, nhả một nút chuột rồi đến nút còn lại, cả hai bên ngoài cửa sổ trình duyệt.

-1

Chà, bạn không thể kiểm tra xem nó có bị hỏng sau sự kiện không, nhưng bạn có thể kiểm tra xem nó có lên không ... Nếu nó kết thúc .. điều đó có nghĩa là không còn bị hỏng nữa: P lol

Vì vậy, người dùng nhấn nút xuống (sự kiện onMouseDown) ... và sau đó, bạn kiểm tra xem có hoạt động không (onMouseUp). Trong khi nó không lên, bạn có thể làm những gì bạn cần.


2
Không phải onMouseUp cũng là một sự kiện sao? Làm thế nào bạn sẽ kiểm tra "tài sản" trênMouseup? Hoặc tài sản của ai, đúng hơn?
Rohit

@Rohit: bạn không kiểm tra thuộc tính, bạn quản lý cờ cho biết sự kiện đã xảy ra ... Nút chuột là lên hoặc xuống.
PhiLho

-1
        var mousedown = 0;
        $(function(){
            document.onmousedown = function(e){
                mousedown = mousedown | getWindowStyleButton(e);
                e = e || window.event;
                console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
            }

            document.onmouseup = function(e){
                mousedown = mousedown ^ getWindowStyleButton(e);
                e = e || window.event;
                console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
            }

            document.oncontextmenu = function(e){
                // to suppress oncontextmenu because it blocks
                // a mouseup when two buttons are pressed and 
                // the right-mouse button is released before
                // the other button.
                return false;
            }
        });

        function getWindowStyleButton(e){
            var button = 0;
                if (e) {
                    if (e.button === 0) button = 1;
                    else if (e.button === 1) button = 4;
                    else if (e.button === 2) button = 2;  
                }else if (window.event){
                    button = window.event.button;
                }
            return button;
        }

phiên bản trình duyệt chéo này hoạt động tốt với tôi.

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.