JavaScript: Проверьте, нажата ли кнопка мыши?

136

Есть ли способ определить, находится ли кнопка мыши в данный момент в JavaScript?

Я знаю о событии "mousedown", но это не то, что мне нужно. Через некоторое время после нажатия кнопки мыши я хочу определить, нажата ли она по-прежнему.

Это возможно?

TM.
источник
14
Почему вы принимаете ответ, который не отвечает на ваш вопрос. Регистрация mousedown и mouseup неверна (так как вы можете мышить вне браузера и позволить ему думать, что вы все еще тянете). Приходить после вашей проблемы и попадать на эту страницу совершенно бесполезно
Джек
@ Джек, это действительно отвечает на мой вопрос. Пожалуйста, прочитайте мой вопрос, а затем прочитайте ответ. Очевидно, более 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 не генерирует события mouseup, если первоначальный mousedown произошел на полосе прокрутки. Пример из этой проблемы Chrome / Chromium . Таким образом, ваша левая кнопка мыши будет внизу навсегда, если есть полоса прокрутки, которую кто-то использует! (В Chrome)
KajMagnus
1
Мне нравится ваше решение, но что, если мышь идет из другого приложения, скажем "ms word", и она перетаскивает какой-то текст. Как вы обнаружите, что мышь не работает?
Шадрак Б. Орина
6
Я не понимаю, почему вы увеличиваете массив mousedown elts во втором примере. Почему счетчик для каждой кнопки, а не 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 отменяет свою игру, это должно стать проще.

Jono Job
источник
6
Этот код проверяет, нажата ли ТОЛЬКО основная кнопка, и требует, чтобы все остальные кнопки были нажаты. (например, если нажаты и первичная, и вторичная, e.buttonsбудет 1+2=3, поэтому e.buttons === 1будет ложным). Если вы хотите проверить, не нажата ли основная кнопка, но не заботитесь о других состояниях кнопок, сделайте следующее:(e.buttons & 1) === 1
AJ Richardson
У меня есть ситуация, когда я ожидаю, что во время перемещения мыши я должен получить код кнопок равным «1», но он выдает «7», - вся работа на Chrome. У кого-нибудь есть идеи?
Василий Холл
@VasilyHall Глядя на документы MDN для MouseEvent.buttons, кажется, это 7означает, что он думает, что кнопки Primary, Secondary и Auxilary все нажаты вместе. Я не уверен, почему это так - вы используете продвинутую мышь? Если так, возможно, стоит попробовать базовый. Если вам нужно только запустить его, вы можете использовать побитовую проверку, чтобы убедиться, что левая кнопка нажата, и игнорировать любые другие. например. 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.
}
paxdiablo
источник
+1 и спасибо. Я думал, что, возможно, придется прибегнуть к этому, но я надеялся, что есть какая-то особенность, которая позволяет просто проверять состояние напрямую.
ТМ.
12
Есть ли причина не использовать логическое значение?
Моала
1
@moala Я думаю, что Int, кажется, меньше печатает, и в конечном счете немного лучше производительность: jsperf.com/bool-vs-int
Джонатан Элмор
12

решение не хорошее. можно «навести» на документ, затем «навести курсор мыши» за пределы браузера, и в этом случае браузер все еще будет думать, что мышь не работает.

Единственное хорошее решение - использовать объект IE.event.

Альфред
источник
11
Я вижу, откуда вы, но решение, которое работает только для IE, тоже не очень хорошее решение.
ТМ.
@alfred В некоторых случаях это может помочь узнать, находится ли перемещение мыши за окном. Если (event.target.nodeName.toLowerCase === 'HTML') вниз = 0;
BF
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>

Селектор: active обрабатывает щелчок мыши намного лучше, чем мышь вверх / вниз, вам просто нужен способ чтения этого состояния в событии onmousemove. Для этого мне нужно было обмануть и полагаться на то, что курсором по умолчанию является «авто», и я просто изменяю его на «по умолчанию», то есть то, что автоматически выбирает по умолчанию.

В объекте вы можете использовать все, что возвращает getComputedStyle, которое вы можете использовать в качестве флага, не нарушая внешний вид вашей страницы, например, border-color.

Мне бы хотелось установить свой собственный стиль в разделе: active, но я не смог заставить его работать. Было бы лучше, если это возможно.

Мартин
источник
Спасибо, что поделились этим. Я использовал эту идею для моделирования логики перетащить-н-капли, но столкнулся вопрос о IE и должен был включать в себя дополнительную логику
eyüp Yusein
4

Следующий фрагмент попытается выполнить функцию doStuff через 2 секунды после события mouseDown в document.body. Если пользователь поднимает кнопку, происходит событие mouseUp и отменяется отложенное выполнение.

Я бы посоветовал использовать какой-либо метод для прикрепления кросс-браузерного события - явная установка свойств mousedown и mouseup была сделана для упрощения примера.

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
}

источник
Это неплохая идея, Джейк. Вам нужно очиститьInterval () в 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 важно, потому что он гарантирует, что события mouseup за пределами окна по-прежнему записываются.

Мика Миллер-Эшлеман
источник
1

Используя API MouseEvent , чтобы проверить нажатую кнопку, если есть:

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)
NVRM
источник
0

Используя jQuery, следующее решение обрабатывает даже «перетащить страницу, а затем освободить регистр».

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

Я не знаю, как он обрабатывает несколько кнопок мыши. Если бы был способ запустить щелчок за пределами окна, а затем ввести мышь в окно, то это, вероятно, также не будет работать должным образом.

Дэвид
источник
0

Ниже приведен пример jQuery, когда мышь находится над $ ('. Element'), цвет меняется в зависимости от того, какая кнопка мыши нажата.

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событие в одном из этих случаев:

  • Пользователь одновременно нажимает клавишу клавиатуры и кнопку мыши, отпускает кнопку мыши за пределами окна браузера и затем отпускает клавишу.
  • пользователь нажимает две кнопки мыши одновременно, отпускает одну кнопку мыши, а затем другую, обе за пределами окна браузера.
dreadcast
источник
-1

Ну, вы не можете проверить, не горит ли он после события, но вы можете проверить, горит ли он ... Если он горит ... это означает, что больше не гаснет: P lol

Таким образом, пользователь нажимает кнопку вниз (событие onMouseDown) ... и после этого вы проверяете, активен ли он (onMouseUp). Пока это не так, вы можете делать то, что вам нужно.

rogeriopvl
источник
2
Разве onMouseUp тоже не событие? Как вы будете проверять "свойство" на домене? Или чья собственность, скорее?
Рохит
@Rohit: вы не проверяете свойство, вы управляете флагом, указывающим, что событие произошло ... Кнопка мыши находится либо вверх, либо вниз.
Фил
-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;
        }

эта кросс-браузерная версия отлично работает для меня.

user2550945
источник