Контекстное меню

Этот урок покажет вам, как создать свой собственный плагин контекстного меню. Окончательный результат будет состоять из одного файла JavaScript и одного файла CSS, который можно легко подключить на веб-страницы.

В интересах надлежащей практики плагин будет создаваться используя руководство принципов предлагаемые jQuery.

Основа плагина

Плагин для контекстного меню называться Audero, код плагина написан Aurelio De Rosa. Плагин можно называть как хотите! Основной файл JavaScript берется из страницы руководства jQuery. Подводя итог, мы будем использовать IIFE чтобы убедиться, что плагин не конфликтует с другими библиотеками, которые используют знак доллара, таких как Prototype. Мы будем также использовать уникальные названия, чтобы быть уверенными, что плагин не будет выполнять другие существующие коды подключенные к той же странице. Выбранное название auderoContextMenu. Смотрите 2-ю строку фрагмента кода, мы добавим к названию объекта $.fn и поместим его в литерал, как это было рекомендовано принципами руководства. Методы плагина потом можно вызвать, передав имя метода в виде строки:

(function($) {
$.fn.auderoContextMenu = function(method) {
  if (methods[method])
      return methods[method].apply(this, 
  Array.prototype.slice.call(arguments, 1));
  else if (typeof method === 'object' || typeof method === 'string' || ! method)
      return methods.init.apply(this, arguments);
  else
  $.error('Method ' + method + ' does not exist on jQuery.auderoContextMenu');
  };
})(jQuery);

Смотрите, положение else if немного отличается от принципов руководства. Мы добавили тест, чтобы проверить, является ли параметр method строкой. Это позволяет пользователю использовать плагин просто проходя один параметр, который должен быть идентифицирован из пользовательского контекстного меню. Это означает, что мы строим контекстное меню, которое будет просто списком DOM. Плагин работает путем замены по умолчанию после клика правой кнопкой мыши на событие, но, как вы увидите позже, для левой кнопкой мыши тоже можно сделать.

к меню ↑

Приступая к работе

Итак, у нас есть код который выполняет метод invoke, вместе с некоторыми другими параметрами. Следующий вопрос: какие методы нужны? Браузер сам не сделает контекстное меню, значит нам нужны методы чтобы показать или скрыть меню. Еще нам нужен метод initialize контекстного меню и некоторые настройки по умолчанию.

Список компонентов:

  1. методы init(), show(), hide()
  2. default settings — настройки по умолчанию

Каждый элемент будет полностью независим друг от друга. Для создания нескольких контекстных меню необходимо внести изменения в наш код.

Давайте взглянем на то, как изменить плагин:

(function($) {
  // значения по умолчанию используются для меню
  var defaultValues = {'idMenu': null, 'posX': null, 'posY': null};
  // настройки для всех элементов меню и, указанный пользователем
  var elementsSettings = {};
  var methods = { /* здесь мы напишем init, методы показать и скрыть */ }
    $.fn.auderoContextMenu = function(method) {
    // Вот код, показанный ранее
    };
})(jQuery);

Рассмотрим подробно методы упомянутые выше

к меню ↑

Init()

Этот метод как и следовало ожидать, инициализирует параметры из контекстного меню, и переопределяет поведение по умолчанию клик правой кнопкой мыши на событие. Он также определяет клик элемента выбранный в контекстном меню, и его расположение. Метод init() принимает один параметр, который может быть объектом строки. Объект должен содержать идентификатор id меню, и координаты для его размещения. Если пользователь видит объект, он будет объединен с использованием настроек по умолчанию метода jQuery extend().

Если строка для показа использует идентификатор меню:

this.on('contextmenu auderoContextMenu', function(event) {
  event.preventDefault();
  event.stopPropagation();
  var params = $.extend({}, elementsSettings[id]);
  if (elementsSettings[id].posX == null || elementsSettings[id].posY == null) {
  params.posX = event.pageX; params.posY = event.pageY;
}
methods.show(params, event, id);
});

Очевидно, что наиболее важная часть этого метода заключается в замене контекстное меню по умолчанию. Для подключения пользовательского меню, мы должны рассмотреть события ContextMenu с помощью jQuery on() method. Функция on() принимает обратный вызов в качестве второго параметра. Функция обратного вызова предотвращает поведение по умолчанию и отображаются в корне контекстного меню браузера. Затем мы проверяем меню, должно быть показано в фиксированном положении или по клику координат. Последняя часть функций вызовов в нашем плагине это метод show().

к меню ↑

show()

Метод show() покажет меню в нужном положении. Этот метод скроет меню которое показано, потому что это уже может быть отображено из-за предыдущего метода вызова. Меню можно скрыть с помощью метода jQuery hide(), но поскольку наш плагин определяет метод hide(), мы будем использовать наш метод как показано ниже.

methods.hide (idMenu);

Следующий шаг будет либо использовать координаты предоставленные пользователем или использовать координаты мыши в момент клика.

Код для события:

if (typeof params !== 'object' || params.posX == undefined || params.posY == undefined) {
  if (event == undefined) {
      params = {'idMenu': params, 'posX': 0, 'posY': 0}
  } else {
      params = {'idMenu': params, 'posX': event.pageX, 'posY': event.pageY}
  }
}

Код, который отображает меню простой. Мы используем jQuery чтобы получить меню через его id, а затем установим позицию (в пикселях), начиная с верхнего левого угла. Метод jQuery show() используется для отображения меню. Благодаря цепочки jQuery эти шаги будут выполнены с помощью только одного оператора, как показано ниже.

Теперь наше удивительное меню появляется волшебным образом:

$('#' + idMenu)
.css('top', params.posY + 'px')
.css('left', params.posX + 'px')
.show();
к меню ↑

hide()

Метод hide() будет использоваться для скрытия меню. Поскольку наш плагин отображает несколько контекстных меню одновременно, будет удобно иметь возможность скрыть все меню за один раз. Метод hide() принимает один необязательный параметр, который представляет меню и будут скрыто. Если задан, то параметр может быть строкой или массивом строк. Если параметр имеет значение null или undefined, то все меню в elementsSettings будет рекурсивно скрытое.

hide: function(id) {
  if (id === undefined || id === null) {
  for(var Key in elementsSettings)
      methods.hide(elementsSettings[Key].idMenu);
  } else if ($.isArray(id)) {
  for(i = 0; i < id.length; i++)
      methods.hide(id[i]);
  } else
$('#' + id).hide();
}
к меню ↑

Добавим CSS

Если мы хотим скрыть список который содержит меню и показать его только при необходимости. Кроме того, мы должны использовать абсолютное позиционирование, чтобы переместить элемент вокруг этой страницы. Последние соответствующим выбором является использование границы, чтобы отделить различные элементы меню.

Код CSS:

ul.audero-context-menu {
   position: absolute;
   display: none;
   background-color: menu;
   list-style-type: none !important;
   margin: 0px !important;
   padding: 0px !important;
}

ul.audero-context-menu * {
   color: menutext;
}

ul.audero-context-menu > li {
   border: 1px solid black;
   margin: 0px !important;
   padding: 2px 5px !important;
}

ul.audero-context-menu > li:hover {
   background-color: activecaption;
}

ul.audero-context-menu > li a {
   display: block;
}
к меню ↑

Применить плагин

Наш плагин очень прост в использовании. В самом деле, его основное использование состоит только из одной строки кода.

Например, предположим что у нас есть следующий фрагмент HTML:

<ul id="context-menu" class="audero-context-menu">
  <li><a href="http://htmlhook.ru">Главная</a></li>
  <li><a href="http://htmlhook.ru/soft">Программы</a></li>
</ul>
<div id="area">Кликнуть здесь, чтобы посмотреть меню.</div>

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

$(document).ready (function() {
$('#area').auderoContextMenu('context-menu');
});

Для левой кнопки мыши такой код.

$(document).ready (function() {
$('#area').auderoContextMenu('context-menu');
});