JavaScript: Перевірте, чи натиснута кнопка миші?


136

Чи є спосіб виявити, чи в даний момент кнопка миші в JavaScript відсутня?

Я знаю про подію "mousedown", але це не те, що мені потрібно. Деякий час ПІСЛЯ натискання кнопки миші я хочу мати можливість виявити, чи вона все ще натиснута вниз.

Чи можливо це?


14
Чому ви приймаєте відповідь, яка не відповідає на ваше запитання. Реєстрація mousedown та mouseup неправильна (оскільки ви можете мишати за межами веб-переглядача та давати йому думку, що ви все ще перетягуєтесь). Потрапити після вашої проблеми і дійти до цієї сторінки абсолютно марно
Джек

@Jack це відповідає на моє запитання. Будь ласка, прочитайте моє запитання, а потім прочитайте відповідь. Мабуть, понад 100 інших людей згодні, що це була хороша відповідь.
ТМ.

4
так ... але мені, Альфреду та ін. 8, я кажу вам, що відстеження миші та маудаун не є правильним способом. Правильна відповідь повинна включати аналіз об’єкта події в обраному вами обробці або аналіз усіх пов'язаних з мишею подій (наприклад, введення / виходу), якщо вам потрібна перевірка, керована часом, а не перевірка, керована подіями.
Джек

На це питання було задано і відповіли 7+ років тому. Я не отримую сповіщення, коли з’являються нові відповіді (але я це роблю для коментарів). Напишіть кращу відповідь, і громада підніме її на початок :) Багато інформації застаріло, і все зміниться.
ТМ.

2
@TM. Вибачте за некроз, але ... Ні, ця інформація ніколи не потрапить до вершини. Після неприйняття власного власника, колись прийнятий, назавжди тримається на вершині. Крім того, "о, так багато людей проголосували за цього" не означає, що відповідь є хорошою; це просто означає, що багато людей це побачили, подумали, що це виглядає добре, і вдарили в нагороду, тому що, здавалося, вони працюють на них.
Фонд позову Моніки

Відповіді:


147

Щодо рішення Pax: воно не працює, якщо користувач навмисно чи випадково натискає більше однієї кнопки. Не запитуйте мене, як я знаю :-(

Правильний код повинен бути таким:

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

З таким тестом:

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

Якщо ви хочете знати, яка кнопка натиснута, будьте готові зробити mouseDown масивом лічильників і рахувати їх окремо для окремих кнопок:

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

Тепер ви можете перевірити, які саме кнопки натискали:

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

Тепер слід попередити, що наведений вище код буде працювати лише для стандартних браузерів, які передають вам номер кнопки, починаючи від 0 і вище. IE використовує трохи маску поточно натиснутих кнопок:

  • 0 за "нічого не натиснуто"
  • 1 зліва
  • 2 справа
  • 4 для середнього
  • і будь-яка комбінація вище, наприклад, 5 для лівого + середнього

Тож відповідно відрегулюйте свій код! Я залишаю це як вправу.

І пам’ятайте: IE використовує глобальний об'єкт події, який називається ... "подія".

Між іншим, у IE є функція, корисна у вашому випадку: коли інші браузери надсилають "кнопку" лише для подій кнопки миші (onclick, onmousedown та onmouseup), IE також надсилає його і onmousemove. Таким чином, ви можете почати слухати onmousemove, коли вам потрібно знати стан кнопки, і перевірити наявність evt.button, як тільки ви його отримали - тепер ви знаєте, які кнопки миші були натиснуті:

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

Звичайно, ви нічого не отримуєте, якщо вона грає мертвою і не рухається.

Відповідні посилання:

Оновлення №1 : Я не знаю, чому я переніс код коду в стилі document.body. Краще буде приєднати обробників подій безпосередньо до документа.


1
Після тестування виявляється, що evt.button насправді не існує в режимі миші з IE7 ...
TM.

5
Я думаю, що це не буде працювати в Chrome, тому що Chrome не генерує події миші, якщо оригінальний мусоун стався на панелі прокрутки. Приклад із цього випуску Chrome / Chromium . Тож ваша ліва кнопка миші буде назавжди знищена, якщо є смуга прокрутки, яку хтось використовує! (В Chrome)
KajMagnus

1
Мені подобається ваше рішення, але що робити, якщо миша надходить з іншої програми, скажіть ms word та її перетягування тексту. Як ви виявите, що мишка вниз?
Шадрак Б. Оріна

6
Я не розумію, чому ви збільшуєте ельти масиву mousedown у другому прикладі. Чому лічильник для кожної кнопки, а не bool для кожної кнопки?
amwinter

2
Це дійсно популярне питання (і відповідь). Я здивований, що це ще не з’явилося, але вам зовсім не потрібно зберігати дані миші. Ви можете просто підключити event.buttonsбудь-який тригер події, який ви використовуєте, без зовнішніх збережених змінних. Я поставив зовсім нове запитання (оскільки моя подія миші не завжди спрацьовує, тому це рішення не працює для мене), і я отримав цю відповідь, можливо, через 5 хвилин.
RoboticRenaissance

32

Це старе питання, і відповіді тут, здається, в основному виступають за використання mousedownта mouseupвідстеження того, чи натиснута кнопка. Але, як зазначали інші, mouseupзапускається лише тоді, коли виконується в браузері, що може призвести до втрати сліду стану кнопки.

Однак MouseEvent (зараз) вказує, які кнопки в даний час натиснуті:

  • Для всіх сучасних браузерів (крім Safari) використовується MouseEvent.buttons
  • Для Safari використовуйте MouseEvent.which( buttonsбуде невизначено для Safari) Примітка: whichвикористовуються різні цифри від buttonsклавіш правого та середнього клацання.

Коли зареєстровано в режимі реєстрації document, mousemoveбуде запущено негайно, як тільки курсор повторно перетвориться на веб-переглядач, тому якщо користувач випустить зовні, стан буде оновлено, як тільки він повернеться мишкою всередину.

Проста реалізація може виглядати так:

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;

Якщо потрібні складніші сценарії (різні кнопки / кілька кнопок / клавіш управління), перегляньте документи MouseEvent. Коли / якщо Safari підніме свою гру, це має стати простішим.


6
Цей код перевіряє, чи ТІЛЬКИ натиснуто первинну кнопку і вимагає, щоб усі інші кнопки були натиснуті. (наприклад, якщо натиснуто і первинний, і вторинний, e.buttonsбуде 1+2=3, значить, e.buttons === 1буде помилковим). Якщо ви хочете перевірити , якщо основна кнопка вниз, але не піклуються про яких - або інших станах кнопки, зробіть наступне:(e.buttons & 1) === 1
AJ Річардсон

У мене є ситуація, коли я очікую, що під час руху миші я повинен отримувати код кнопок "1", але він виробляє "7", - вся робота над Chrome. Хтось має якусь ідею?
Зал Василя

@VasilyHall Дивлячись на документи MDN для MouseEvent.buttons, здається, це 7означає, що він думає, що кнопки "Первинна", "Друга" та "Допоміжні засоби" всі натискаються разом. Я не впевнений, чому це було б так - ви використовуєте сучасну мишу? Якщо так, можливо, варто спробувати з базовим. Якщо вам просто потрібно це зробити, ви можете скористатися побіжною прапорець, щоб переконатися, що ліва кнопка натиснута та проігнорована будь-якими іншими. напр. MouseEvent.buttons & 1 === 1.
Jono Job

Дякую, я використовував свій JavaScript всередині спеціального браузера: вбудований Chrome (ium?) У програмі Adobe Illustrator. Я ставлю на облік, що комбінація всіх різних речей якось призводить до 7, хоча натискається лише одна кнопка . Бачачи, як це відповідає моїй заявці, я просто роблю перевірку на 1 або 7, щоб полегшити інтерактивність. Додам, хоча я використовую Logitech M570 (або будь-яку іншу) трекбольну мишу, вона правильно реєструє 1 у звичайному браузері, але 7 всередині Illustrator.
Зал Василя

16

Я думаю, що найкращим підходом до цього є збереження власного запису про стан кнопки миші таким чином:

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

а потім пізніше у своєму коді:

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

+1, і спасибі Я думав, що, можливо, доведеться вдатися до цього, але сподівався, що є якась особливість, яка дозволяє вам просто перевірити стан безпосередньо.
ТМ.

12
Чи є причина не використовувати булеву форму?
моала

1
@moala Я думаю, що Int здається менш типізованим, і в кінцевому рахунку трохи кращим показником: jsperf.com/bool-vs-int
Johnathan Elmore

12

рішення не добре. можна було б "замурувати" документ, потім "мишати" поза веб-переглядачем, і в цьому випадку браузер все ще думає, що миша вниз.

єдине хороше рішення - використання об'єкта IE.event.


11
Я бачу, звідки ви беретесь, але рішення, яке працює лише для IE, теж не є хорошим рішенням.
ТМ.

@alfred У деяких випадках це може допомогти дізнатися, чи рухається миша у вікні. Якщо (event.target.nodeName.toLowerCase === 'html') вниз = 0;
БФ

6

Я знаю, що це старий пост, але я подумав, що відстеження кнопки миші за допомогою миші вгору / вниз відчувало трохи незграбність, тому я знайшов альтернативу, яка може подобатися деяким.

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

: Активний селектор обробляє клацання миші набагато краще, ніж миша вгору / вниз, вам просто потрібен спосіб зчитування цього стану в події onmousemove. Для цього мені потрібно було обдурити і покладатися на той факт, що курсор за замовчуванням є "auto", і я просто змінюю його на "default", саме це автоматично вибирає за замовчуванням.

Ви можете використовувати будь-що в об'єкті, який повертається getComputedStyle, який ви можете використовувати як прапор, не порушуючи зовнішній вигляд сторінки, наприклад, колір межі.

Мені б хотілося встановити свій власний визначений користувачем стиль у розділі: active, але я не зміг його працювати. Було б краще, якщо це можливо.


Дякуємо, що поділилися цим. Я використав цю ідею для моделювання логіки перетягнути-н-краплі, але зіткнувся питання про IE і повинен був включати в себе додаткову логіку
eyüp Yusein

4

Наступний фрагмент спробує виконати функцію "doStuff" через 2 секунди після події mouseDown у документі document.body. Якщо користувач підніме кнопку, відбудеться подія mouseUp та скасує затримку виконання.

Я б радив використовувати якийсь метод для вкладення подій між веб-переглядачами - встановлення властивостей mousedown та миші явно робилося для спрощення прикладу.

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

Дякую, але це не зовсім та поведінка, яку я шукав (хоча я бачу, як моє запитання вказує, що це те, що я намагаюся зробити).
ТМ.

3

Короткий і солодкий

Я не впевнений, чому жодна з попередніх відповідей не працювала для мене, але я придумав це рішення в момент еврики. Це не тільки працює, але і є найелегантнішим:

Додати до тегу тіла:

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

Потім тестуйте та виконайте, myfunction()якщо downдорівнює 1:

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

4
ви новачок, тому я збираюся трохи допомогти вам тут. По-перше, пам’ятайте про свою граматику в своїх публікаціях - я, мабуть, витратив більше часу на її виправлення, ніж ви вкладаєте її. По-друге, ваше рішення - це лише інша версія перерахованих вище інших - це нічого нового. По-третє, у вашому рішенні використовується техніка, яка називається "використання прапорів", яку Томас Хансен запропонував вище. Будь ласка, подбайте про те, щоб перевірити свою граматику та не повторювати рішення під час публікації на старих публікаціях, не надаючи пояснення, чому інші рішення не працювали для вас.
Захарій Кнібель

5
Я все-таки проголосував за ваше рішення, оскільки це справедливо, і ви новачок у SO
Zachary Kniebel

2

Ви можете поєднати @Pax і мої відповіді, щоб також отримати тривалість, за яку миша була зменшена:

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

Потім пізніше:

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

Це не погана ідея, Джейк. Чи потрібно очистити InterInterval () в onmouseup (), перш ніж встановити mousedown в 0? Я насторожено перемикаю функцію таймера між встановленням на 0 та зупинкою таймера, залишаючи тайм-аут на 200? Аналогічно і в містечку.
paxdiablo

Порядок clearIntervals не змінить значення, оскільки поточна нитка виконання завершиться до початку будь-яких подій (включаючи таймери).
Натаніель Райнхарт

2

Вам потрібно обробити MouseDown і MouseUp і встановити прапор чи щось, щоб відстежувати його "пізніше вниз по дорозі" ... :(


2

Якщо ви працюєте на складній сторінці з існуючими обробниками подій миші, рекомендую обробляти подію під час зйомки (замість бульбашки). Для цього просто встановіть 3-й параметр addEventListenerдо true.

Крім того, ви можете перевірити, event.whichчи не обробляєте ви дійсну взаємодію з користувачем, а не подіями миші, наприклад 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);

Додайте обробник до документа (або вікна) замість document.body важливо b / c, це гарантує, що події миші поза вікном все ще записуються.


1

Використовуючи MouseEvent api, щоб перевірити натиснуту кнопку, якщо така є:

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

Повернення :

Число, що представляє одну або кілька кнопок. Для більш ніж однієї кнопки, натиснутої одночасно, значення поєднуються (наприклад, 3 первинне + вторинне).

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

Використовуючи jQuery, наступне рішення обробляє навіть "перетягнути сторінку, а потім випустити".

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

Я не знаю, як він обробляє декілька кнопок миші. Якби був спосіб запустити клацання поза вікном, а потім принести мишку до вікна, то, ймовірно, і там не працюватиме належним чином.


0

Нижче прикладу jQuery, коли миша перевищує $ ('. Елемент'), колір змінюється залежно від того, яку кнопку миші натискають.

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

Як сказав @Jack, коли mouseupце відбувається поза вікном браузера, ми про це не знаємо ...

Цей код (майже) працював для мене:

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

На жаль, я не отримаю mouseupподію в одному з таких випадків:

  • Користувач одночасно натискає клавішу клавіатури та кнопку миші, відпускає кнопку миші поза вікном браузера, після чого відпускає клавішу.
  • користувач натискає дві кнопки миші одночасно, відпускає одну кнопку миші, а потім іншу, обидві за межами вікна браузера.

-1

Ну, ви не можете перевірити, чи він після події вниз, але ви можете перевірити, чи не вгору ... Якщо це вгору .. це означає, що більше не вниз: P lol

Таким чином, користувач натискає кнопку вниз (подія onMouseDown) ... і після цього ви перевіряєте, чи не працює (onMouseUp). Хоча це ще не вгору, ви можете робити все, що вам потрібно.


2
Чи не onMouseUp подія теж? Як ви будете перевіряти "власність" наMouseup? Або чиє майно, скоріше?
Рохіт

@Rohit: ви не перевіряєте майно, ви керуєте прапором, який вказує, що подія сталася ... Кнопка миші або вгору, або вниз.
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;
        }

ця версія браузера для мене працює чудово.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.