JavaScript: Periksa apakah tombol mouse turun?

136

Adakah cara untuk mendeteksi jika tombol mouse saat ini tidak aktif di JavaScript?

Saya tahu tentang acara "mousedown", tapi bukan itu yang saya butuhkan. Beberapa saat SETELAH tombol mouse ditekan, saya ingin dapat mendeteksi apakah masih ditekan.

Apakah ini mungkin?

TM.
sumber
15
Mengapa Anda menerima Jawaban yang tidak menjawab pertanyaan Anda. Mendaftarkan mousedown dan mouseup salah (karena Anda dapat mengarahkan mouse ke atas di luar browser dan membiarkannya mengira Anda masih menyeret). Mengatasi masalah Anda dan membuka halaman ini sama sekali tidak berguna
Jack
1
@ Jack itu menjawab pertanyaan saya. Silakan baca pertanyaan saya dan kemudian baca jawabannya. Rupanya lebih dari 100 orang setuju bahwa itu adalah jawaban yang bagus.
TM.
4
ya .. tapi saya, alfred, dan 8 lainnya memberi tahu Anda bahwa melacak mouseup dan mousedown bukanlah cara yang benar. Jawaban yang benar harus melibatkan analisis objek peristiwa di penangan pilihan Anda, atau analisis semua peristiwa terkait mouse (seperti masuk / keluar) jika Anda memerlukan pemeriksaan berdasarkan waktu dan bukan pemeriksaan berdasarkan peristiwa.
Jack
1
Pertanyaan ini telah ditanyakan dan dijawab 7+ tahun yang lalu. Saya tidak mendapat notifikasi ketika ada jawaban baru (tapi saya lakukan untuk komentar). Tulis jawaban yang lebih baik dan komunitas akan memilihnya di atas :) Banyak informasi menjadi basi dan banyak hal berubah.
TM.
2
@TM. Maaf necro, tapi ... Tidak, info itu tidak akan pernah sampai ke atas. Sebuah non-self-answer, setelah diterima, menempel di atas selamanya. Juga, "oh begitu banyak orang yang memilih yang ini" tidak berarti jawabannya bagus; itu hanya berarti banyak orang yang melihatnya, menganggapnya baik-baik saja, dan mendapatkan suara positif karena tampaknya berhasil untuk mereka.
Gugatan Dana Monica

Jawaban:

152

Mengenai solusi Pax: tidak berfungsi jika pengguna mengklik lebih dari satu tombol secara sengaja atau tidak sengaja. Jangan tanya saya bagaimana saya tahu :-(.

Kode yang benar harus seperti itu:

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

Dengan tes seperti ini:

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

Jika Anda ingin mengetahui tombol apa yang ditekan, bersiaplah untuk membuat mouseDown sebagai array penghitung dan menghitungnya secara terpisah untuk tombol terpisah:

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

Sekarang Anda dapat memeriksa tombol apa yang ditekan dengan tepat:

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

Sekarang diperingatkan bahwa kode di atas hanya akan berfungsi untuk browser yang memenuhi standar yang memberikan Anda nomor tombol mulai dari 0 dan lebih tinggi. IE menggunakan sedikit topeng dari tombol yang saat ini ditekan:

  • 0 untuk "tidak ada yang ditekan"
  • 1 untuk kiri
  • 2 untuk kanan
  • 4 untuk tengah
  • dan kombinasi apapun di atas, misalnya 5 untuk kiri + tengah

Jadi sesuaikan kode Anda dengan benar! Saya tinggalkan sebagai latihan.

Dan ingat: IE menggunakan objek event global yang disebut… "event".

Secara kebetulan, IE memiliki fitur yang berguna dalam kasus Anda: ketika browser lain mengirim "tombol" hanya untuk aktivitas tombol mouse (onclick, onmousedown, dan onmouseup), IE juga mengirimkannya dengan onmousemove. Jadi, Anda dapat mulai mendengarkan onmousemove saat Anda perlu mengetahui status tombol, dan memeriksa tombol evt. segera setelah Anda mendapatkannya - sekarang Anda tahu tombol mouse apa yang ditekan:

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

Tentu saja Anda tidak mendapatkan apa-apa jika dia berpura-pura mati dan tidak bergerak.

Tautan yang relevan:

Pembaruan # 1 : Saya tidak tahu mengapa saya membawa-bawa kode document.body-style. Akan lebih baik untuk melampirkan penangan kejadian langsung ke dokumen.

Eugene Lazutkin
sumber
1
Setelah pengujian, ternyata tombol evt.button tidak ada di mousemove dengan IE7 ...
TM.
5
Saya rasa ini tidak akan berfungsi di Chrome, karena Chrome tidak menghasilkan peristiwa mouseup jika mousedown asli terjadi di scrollbar. Contoh , dari masalah Chrome / Chromium ini . Jadi tombol kiri mouse Anda akan mati selamanya, jika ada scrollbar yang digunakan seseorang! (Di Chrome)
KajMagnus
1
Saya suka solusi Anda, tetapi bagaimana jika mouse berasal dari aplikasi yang berbeda ucapkan kata ms dan menyeret beberapa teks. Bagaimana Anda mendeteksi bahwa mouse mati?
Shadrack B. Orina
6
Saya tidak mengerti mengapa Anda menambah elemen array mousedown di contoh kedua. Mengapa penghitung untuk setiap tombol daripada bool untuk setiap tombol?
Musim dingin
2
Ini adalah pertanyaan (dan jawaban) yang sangat populer. Saya terkejut ini belum muncul, tetapi Anda tidak perlu menyimpan data mouse sama sekali. Anda cukup menyambungkan event.buttonske pemicu peristiwa apa pun yang Anda gunakan, tanpa variabel simpanan eksternal. Saya mengajukan pertanyaan baru (karena acara mouseup saya tidak selalu aktif, jadi solusi ini tidak berfungsi untuk saya) dan mendapatkan jawaban itu mungkin dalam waktu paling lama 5 menit.
RoboticRenaissance
36

Ini adalah pertanyaan lama, dan jawabannya di sini tampaknya sebagian besar menganjurkan untuk menggunakan mousedowndan mouseupmelacak apakah sebuah tombol ditekan. Namun seperti yang ditunjukkan orang lain, mouseuphanya akan aktif saat dijalankan di dalam browser, yang dapat menyebabkan hilangnya jejak status tombol.

Namun, MouseEvent (sekarang) menunjukkan tombol mana yang saat ini ditekan:

  • Untuk semua penggunaan browser modern (kecuali Safari) MouseEvent.buttons
  • Untuk Safari, gunakan MouseEvent.which( buttonstidak ditentukan untuk Safari) Catatan: whichmenggunakan nomor berbeda dari buttonsuntuk klik Kanan dan Tengah.

Ketika terdaftar pada document, mousemoveakan segera aktif segera setelah kursor masuk kembali ke browser, jadi jika pengguna melepaskan di luar maka status akan diperbarui segera setelah mereka kembali ke dalam.

Penerapan sederhana mungkin terlihat seperti:

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;

Jika skenario yang lebih rumit diperlukan (tombol berbeda / beberapa tombol / tombol kontrol), lihat dokumen MouseEvent. Saat / jika Safari mengangkat permainannya, ini akan menjadi lebih mudah.

Jono Job
sumber
7
Kode ini memeriksa apakah HANYA tombol utama yang ditekan dan semua tombol lainnya harus tidak ditekan. (misalnya jika primer dan sekunder ditekan, e.buttonsakan 1+2=3, jadi e.buttons === 1akan salah). Jika Anda ingin memeriksa apakah tombol utama mati, tetapi tidak peduli dengan status tombol lainnya, lakukan ini:(e.buttons & 1) === 1
AJ Richardson
Saya memiliki situasi di mana saya mengharapkan bahwa selama gerakan mouse saya harus mendapatkan kode tombol menjadi '1' tetapi menghasilkan '7', - semua pekerjaan ada di Chrome. Ada yang punya ide?
Vasily Hall
@VasilyHall Melihat dokumen MDN untuk MouseEvent.buttons, tampaknya itu 7berarti bahwa tombol Utama, Sekunder dan Tambahan semuanya ditekan bersamaan. Saya tidak yakin mengapa ini terjadi - apakah Anda menggunakan mouse tingkat lanjut? Jika demikian, mungkin ada baiknya mencoba dengan yang dasar. Jika Anda hanya ingin menjalankannya, Anda dapat menggunakan pemeriksaan bitwise untuk memastikan bahwa tombol kiri ditekan dan mengabaikan yang lain. misalnya. MouseEvent.buttons & 1 === 1.
Jono Job
Terima kasih, saya menggunakan JavaScript saya di dalam browser khusus: Chrome yang disematkan (ium?) Di dalam aplikasi Adobe Illustrator- Saya yakin kombinasi dari semua hal entah bagaimana mengarah ke 7, meskipun hanya satu tombol yang ditekan . Melihat bagaimana ini konsisten dalam aplikasi saya, saya hanya melakukan pemeriksaan untuk 1 atau 7 untuk memfasilitasi interaktivitas saya. Saya akan menambahkan, meskipun saya menggunakan mouse trackball Logitech M570 (atau apa pun), mouse trackball ini mendaftarkan 1 dengan benar di browser biasa tetapi 7 di dalam Illustrator.
Vasily Hall
16

Saya pikir pendekatan terbaik untuk ini adalah dengan menyimpan catatan Anda sendiri tentang status tombol mouse, sebagai berikut:

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

lalu, nanti di kode Anda:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}
paxdiablo
sumber
+1, dan terima kasih. Saya pikir saya mungkin harus menggunakan ini, tetapi saya berharap ada beberapa fitur yang memungkinkan Anda memeriksa status secara langsung.
TM.
12
Apakah ada alasan untuk tidak menggunakan boolean?
moala
1
@moala Saya pikir Int tampaknya kurang mengetik, dan pada akhirnya kinerja sedikit lebih baik: jsperf.com/bool-vs-int
Johnathan Elmore
12

solusinya tidak bagus. seseorang dapat melakukan "mousedown" pada dokumen, lalu "mouseup" di luar browser, dan dalam hal ini browser akan tetap berpikir mouse sedang down.

satu-satunya solusi yang baik adalah menggunakan objek IE.event.

alfred
sumber
13
Saya melihat dari mana Anda berasal, tetapi memiliki solusi yang hanya berfungsi untuk IE juga bukan solusi yang baik.
TM.
@alfred Dalam beberapa kasus, mungkin membantu untuk mengetahui apakah mousemove di luar jendela. Jika (event.target.nodeName.toLowerCase === 'html') down = 0;
BF
6

Saya tahu ini adalah posting lama, tetapi saya pikir pelacakan tombol mouse menggunakan mouse naik / turun terasa agak kikuk, jadi saya menemukan alternatif yang mungkin menarik bagi sebagian orang.

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

Selektor aktif menangani klik mouse jauh lebih baik daripada mouse atas / bawah, Anda hanya perlu cara membaca status itu di acara onmousemove. Untuk itu saya perlu menipu dan mengandalkan fakta bahwa kursor default adalah "auto" dan saya hanya mengubahnya menjadi "default", yang secara otomatis memilih default.

Anda dapat menggunakan apa pun di objek yang dikembalikan oleh getComputedStyle yang dapat Anda gunakan sebagai bendera tanpa mengganggu tampilan halaman Anda, misalnya warna batas.

Saya ingin mengatur gaya saya sendiri yang ditentukan pengguna di: bagian aktif, tetapi saya tidak bisa membuatnya bekerja. Akan lebih baik jika memungkinkan.

Martin
sumber
Terima kasih telah membagikan ini. Saya menggunakan ide ini untuk logika gaya drag-n-drop, tetapi menghadapi masalah di IE dan harus menyertakan logika tambahan
Eyup Yusein
4

Cuplikan berikut akan mencoba menjalankan fungsi "doStuff" 2 detik setelah peristiwa mouseDown terjadi di document.body. Jika pengguna mengangkat tombol, peristiwa mouseUp akan terjadi dan membatalkan eksekusi yang tertunda.

Saya akan menyarankan menggunakan beberapa metode untuk lampiran acara lintas-browser - mengatur properti mousedown dan mouseup secara eksplisit dilakukan untuk menyederhanakan contoh.

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

sumber
Terima kasih, tetapi ini bukanlah perilaku yang saya cari (meskipun saya dapat melihat bagaimana pertanyaan saya menunjukkan bahwa inilah yang saya coba lakukan).
TM.
3

Pendek dan manis

Saya tidak yakin mengapa tidak ada jawaban sebelumnya yang berhasil untuk saya, tetapi saya menemukan solusi ini selama momen eureka. Ini tidak hanya berfungsi, tetapi juga paling elegan:

Tambahkan ke tag tubuh:

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

Kemudian uji dan jalankan myfunction()jika downsama dengan 1:

onmousemove="if (down==1) myfunction();"
Stanley
sumber
4
Anda baru, jadi saya akan membantu Anda sedikit, di sini. Pertama, perhatikan tata bahasa Anda dalam posting Anda - Saya mungkin menghabiskan lebih banyak waktu untuk memperbaikinya daripada yang Anda masukkan ke dalamnya. Kedua, solusi Anda hanyalah versi lain dari yang lain yang tercantum di atas - ini bukan hal baru. Ketiga, solusi Anda menggunakan teknik yang disebut sebagai "menggunakan bendera", yang disarankan oleh Thomas Hansen di atas. Harap berhati-hati untuk memeriksa tata bahasa Anda dan jangan mengulangi solusi saat memposting ke posting lama tanpa memberikan penjelasan tentang mengapa solusi lain tidak berhasil untuk Anda.
Zachary Kniebel
5
Saya lakukan, namun pilih solusi Anda, karena IS valid dan Anda baru
mengenal
3

Jika Anda bekerja di dalam halaman yang kompleks dengan event handler mouse yang ada, saya sarankan untuk menangani event tersebut saat ditangkap (bukan gelembung). Untuk melakukan ini, cukup setel parameter ke-3 dari addEventListenermenjadi true.

Selain itu, Anda mungkin ingin memeriksa untuk event.whichmemastikan Anda menangani interaksi pengguna yang sebenarnya dan bukan kejadian mouse, mis 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);

Tambahkan penangan ke dokumen (atau jendela) alih-alih document.body penting b / c ini memastikan bahwa peristiwa mouseup di luar jendela masih direkam.

Micah Miller-Eshleman
sumber
2

Anda dapat menggabungkan @Pax dan jawaban saya untuk juga mendapatkan durasi mouse turun selama:

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

Kemudian nanti:

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

sumber
Itu bukan ide yang buruk, Jake. Apakah Anda perlu menghapus Interval () di onmouseup () sebelum menyetel mousedown ke 0? Saya waspada terhadap fungsi pengatur waktu yang aktif antara menyetelnya ke 0 dan menghentikan pengatur waktu, meninggalkan batas waktu pada 200? Begitu pula di onmousedown.
paxdiablo
Urutan clearIntervals tidak akan membuat perbedaan karena rangkaian eksekusi saat ini akan selesai sebelum peristiwa apa pun (termasuk pengatur waktu) diaktifkan.
Nathaniel Reinhart
2

Anda perlu menangani MouseDown dan MouseUp dan menyetel beberapa bendera atau sesuatu untuk melacaknya "nanti di jalan" ... :(

Thomas Hansen
sumber
1

Menggunakan api MouseEvent , untuk memeriksa tombol yang ditekan, jika ada:

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

Kembali :

Angka yang mewakili satu atau lebih tombol. Untuk lebih dari satu tombol yang ditekan secara bersamaan, nilainya digabungkan (misalnya, 3 adalah primer + sekunder).

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)
NVRM
sumber
0

Menggunakan jQuery, solusi berikut bahkan menangani "seret halaman lalu lepaskan kasus".

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

Saya tidak tahu bagaimana cara menangani beberapa tombol mouse. Jika ada cara untuk memulai klik di luar jendela, lalu mengarahkan mouse ke jendela, ini mungkin juga tidak akan berfungsi dengan baik di sana.

David
sumber
0

Di bawah contoh jQuery, ketika mouse lebih dari $ ('. Element'), warna berubah tergantung pada tombol mouse mana yang ditekan.

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();
});
Marcin Żurek
sumber
0

Seperti yang dikatakan @Jack, kapan mouseup terjadi di luar jendela browser, kami tidak menyadarinya ...

Kode ini (hampir) berfungsi untuk saya:

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

Sayangnya, saya tidak akan mendapatkan mouseupacara di salah satu kasus tersebut:

  • pengguna secara bersamaan menekan tombol keyboard dan tombol mouse, melepaskan tombol mouse di luar jendela browser lalu melepaskan tombol.
  • pengguna menekan dua tombol mouse secara bersamaan, melepaskan satu tombol mouse lalu tombol lainnya, keduanya di luar jendela browser.
dreadcast
sumber
-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;
        }

versi lintas-browser ini berfungsi dengan baik untuk saya.

pengguna2550945
sumber
-2

Nah, Anda tidak bisa mengecek apakah turun setelah acara, tapi Anda bisa mengecek apakah itu Naik ... Jika sudah naik .. artinya tidak lagi turun: P lol

Jadi pengguna menekan tombol bawah (acara onMouseDown) ... dan setelah itu, Anda memeriksa apakah sudah naik (onMouseUp). Meskipun belum habis, Anda dapat melakukan apa yang Anda butuhkan.

rogeriopvl
sumber
2
Bukankah onMouseUp juga sebuah acara? Bagaimana Anda akan memeriksa "properti" onMouseup? Atau milik siapa?
Rohit
@Rohit: Anda tidak memeriksa properti, Anda mengelola sebuah bendera yang menandakan peristiwa telah terjadi ... Tombol tetikusnya naik atau turun.
PhiLho