Javascript — Middle Button Click

Март 14th, 2010 по Perlover Оставить ответ »

Открываю тему программирования на JavaScript. Недавно решал проблему, казалось бы, тривиальной задачи отслеживания такого события, как middleclick mouse — клик колесиком мышки. Но на деле, такая задача далеко не тривиальная — об этом вы даже можете прочесть в хорошей и подробно описывающей статье на английском языке про события в разных броузерах.

Итак, в самом JavaScript есть такое событие клика мышки — тип ‘click’. Но данное событие вырабатывается только при клике левой кнопкой мыши (исключения — IE & Safari). Стандарт W3C описывает событие click, но там не сказано про то, от какой кнопки мыши оно должно происходить. Видимо, от этого в броузерах наблюдается полная анархия с этим делом.

Зачем мне понадобилось отслеживать событие middle click? Например, в броузере Firefox (в Chrome и Internet Explorer 7.0 и выше) клик колесиком мышки по ссылке приводит к ее открытию в новом табе в фоновом режиме, и страница, на которой кликают, продолжает «висеть» перед глазами пользователя. Мне лично нравиться так «сёрфить», так как это удобно, и следовательно, подумал я, так делают многие (по моим последним данным, рассчитанным на основе 65 тыс. кликов — 2.5% из них — клик колесиком мышки). Но, к сожалению, такой удобный клик не генерирует событие ‘click’ на уровне API разработчика. Мне нужно было отслеживать клики для сбора статистики, и для полноты картины я хотел учитывать даже эти клики. Но такого типа события в броузерах нет. Что делать?

Для начала, хочу сказать, что этот дурацкий Internet Explorer (ужасный броузер, особенно для программиста JavaScript) все таки генерирует событие ‘click’ на клик колесиком (Safari также). То есть под IE можно не стараться отслеживать его, а просто отследить событие click (там также middleclick открывает ссылку в новом табе). А вот с Firefox и другими (Opera 8.x и новее, например) придется постараться. Они генерируют только события mousedown & mouseup и все. Чтобы понять событие, надо отследить оба эти и еще одно событие — не ушла ли мышка на другой объект — ведь если между нажатием и отпусканием колесика пользователь двигал мышкой — событием клика это нельзя считать.

Я написал и использую два варианта кода — один для jQuery, другой в проектах, где jQuery не используется. Вот куски кодов:

jQuery:

jQuery.event.special.middleclick = {
    setup: function(data, namespaces) {
        var elem = this, $elem = jQuery(elem);
        $elem.bind('mousedown mouseup mouseout', jQuery.event.special.middleclick.handler);
    },

    teardown: function(namespaces) {
        var elem = this, $elem = jQuery(elem);
        $elem.unbind('mousedown mouseup mouseout', jQuery.event.special.middleclick.handler);
    },

    handler: function(event) {
        var elem = this, $elem = jQuery(elem);
        if (event.type == 'mousedown' && event.which == 2)
          $elem.data('mouseTrigger', 1);
        else
          if (event.type == 'mouseout')
            $elem.data('mouseTrigger', 0);
          else
            if (event.type == 'mouseup')
             {
              if (event.which == 2 && $elem.data('mouseTrigger'))
               {
                event.type = "middleclick";
                jQuery.event.handle.apply(this, arguments)
               }
              $elem.data('mouseTrigger', 0);
             }
    }
};

JavaScript без jQuery:

mouseTrigger = function (elem, event)
{
 var nButton;

 if (document.all)
  {
   event = window.event;
   nButton = 4;
  }
 else
  {
   nButton = 1;
  }
 if (event.type == 'mousedown' && event.button == nButton)
   elem.mouseTrigger = 1;
 else
   if (event.type == 'mouseout')
     elem.mouseTrigger = 0;
   else
     if (event.type == 'mouseup')
      {
       if (event.button == nButton && elem.mouseTrigger)
         ourHandler(elem);
       elem.mouseTrigger = 0;
      }
 return true;
}

Оба эти способа требуют установки обработчика событий — handler в виде функции function () {}. И тут есть важный момент. Поскольку оба моих предложенных варианта работают как под IE, так и под Firefox, возникает проблема в IE — сначала происходит моё событие и дергает ваш handler, затем IE производит событие click, которые, как правило, обрабатываются тем же обработчиком (я привожу в пример вариант, когда мы хотим отслеживать все клики по линкам — и обычные, и middleclick). То есть в IE на один клик колесиком мышки дергается два раза handler. Самым простым и эффективным решением лично я нашел способ исключения второго клика путем замерения времени — если наш handler на тот же элемент DOM дергают два раза с разницой менее 500 мс, значит это IE с его вторым click:

jQuery:

Для jQuery варианта наш handler должен выглядеть и устанавливаться так (для всех линков, которые залинкованы на картинки, например):

$('a > img').bind('click middleclick', function (event)
   {
    var now = +new Date;
    if ($(this).data('lastClick') && now - $(this).data('lastClick') < 500)
      return; // Дубликат клика, например IE
    $(this).data('lastClick', now);

    // Здесь уже идет код нашего обработчика ...
   });

В этом примере, мы ищем все линки, которые линкуются на картинки, и ставим на них обработку двух событий — события ‘click’ и своего события ‘middleclick’. Последнее событие реализовано через API jQuery как свой новый тип события — ‘middleclick’.

JavaScript без jQuery:

function ourHandler(elem)
{
var now = +new Date;
if (elem.lastClick && now - elem.lastClick < 500)
return;
elem.lastClick = now;

// Здесь уже идет код нашего обработчика ...
}

На этом я заканчиваю эту статейку. Надеюсь, эти примеры помогут вам лучше отслеживать клики на ваших страницах 🙂

QR-Code этой страницы:

5 комментария

  1. Kaktus:

    Ура. Есть еще сайты с полезным контентом. Пару часов искал перехват событий на странице (click, mouseover, mouseout). вроде бы нашел.. Спасибо.

  2. Kaktus:

    в смысле чтобы без JQ

  3. Kolridg:

    Для статистики пропущен еще один способ открытия: правый клик — панель опций — открыть на новой вкладке

  4. Perlover:

    Kolridg, спасибо!
    А это точно не работает как просто событие onclick?
    Но в любом, случае, мне кажется, что это событие делают гораздо меньшее количество пользователей, чем даже клик мышкой (которое, по моим данным, составляем 2-3% от всех типов кликов) — потому что, чтобы его выполнить, необходимо проделать много действий.

  5. Спасибо. Всё получилось :). Вот бы ещё найти как при клике на колёсико запретить браузеру открывать ссылку в новой вкладке