Я доделал свой плагин, прошу оценки, советов по модернизации.
/* ------------------------------------------------------------------
Плагин выпалывающего меню .DropDown()
Опции:
button_element: 'a', Ссылка на кнопку для открытия меню
menu_element: 'ul', Ссылка на дочернее меню
event: 'hover', Событие для открытия меню hover или click
animate: 'slide', Название анимации none, fade или slide
animate_duraction: 500, Скорость анимации в миллисекундах
open_class: 'open', Класс для открытого меню
wrap_class: 'dropdown', Класс обёртки меню
button_class: 'dropdown-button', Класс кнопки меню
menu_class: 'dropdown-menu' Класс по меню
События:
render.dropdown Визуализация, добавление нужных стилей, классов
open.dropdown Открытие меню
close.dropdown Закрытие меню
Методы:
init Вызывается по умолчанию, инициализирует плагин
update Обновляет настройки плагина
destroy Удаляет работу плагина
Пример:
HTML:
<div class="menu">
<a href="#">Открыть</a>
<ul>
<li><a href="#">Пункт 1</a></li>
<li><a href="#">Пункт 2</a></li>
<li><a href="#">Пункт 3</a></li>
</ul>
</div>
JS:
$(".menu").DropDown();
P.S. Это меню изначально придумано для WordPress, но подойдёт практически для
чего угодно так как оно требует минимальной вёрстки, и очень хорошо настраивается.
------------------------------------------------------------------ */
;(function ($) {
"use strict";
$.fn.DropDown = function(method, options) {
var defaults, methods;
// Если не указаны пользовательские настройки
if(options === undefined) {
options = {};
// Если пользователь не указал метод но указал свои настройки
if(typeof method === 'object') {
options = method;
}
}
// Стандартные настройка
defaults = {
button_element: 'a',
menu_element: 'ul',
menu_width: '200px',
event: 'hover',
animate: 'slide',
animate_duraction: 500,
open_class: 'open',
wrap_class: 'dropdown',
button_class: 'dropdown-button',
menu_class: 'dropdown-menu'
};
// Методы плагина
methods = {
init: function () {
// Цикл по всем элементам
return this.each(function () {
var $wrap, $button, $menu, data, vars;
// Обёртка меню
$wrap = $(this);
// Получение data настроек
data = $wrap.data('dropdown');
data = !data ? {} : data;
// Выходим если инициализация уже была
if (data.init) return false;
data.init = true;
// Обледенением стандартные и пользовательские настройки
vars = $.extend({}, defaults, data, options);
$wrap.data('dropdown', vars);
// Элементы меню
$button = $wrap.children(vars.button_element);
$menu = $wrap.children(vars.menu_element);
// Визуализация
$wrap
.addClass(vars.wrap_class)
.trigger('render.dropdown');
$menu
.addClass(vars.menu_class)
.css('display', 'none');
$button.addClass(vars.button_class);
// Открытие закрытие меню
switch (vars.event) {
// При наведении
case 'hover':
$wrap.on('mouseenter.dropdown', function () {
open($(this));
}).on('mouseleave.dropdown', function () {
close($(this));
});
break;
// При клике
default:
$button.on('click.dropdown', function () {
var $this_wrap = $(this).parent($wrap);
if($this_wrap.hasClass(vars.open_class)) {
close($this_wrap);
} else {
open($this_wrap);
}
});
// При клике вне меню закрываем его
$(document).on('click.dropdown', function (event) {
if ($(event.target).closest($wrap).length) return;
close($wrap);
event.stopPropagation();
});
break;
}
});
},
update: function() {
methods.destroy.apply(this, options);
methods.init.apply(this, options);
},
destroy: function() {
var $wrap, vars, $button, $menu;
// Обёртка
$wrap = $(this);
// Настройки
vars = $wrap.data('dropdown');
// Элементы меню
$button = $wrap.children(vars.button_element);
$menu = $wrap.children(vars.menu_element);
// Если плагин не инициализирован то выходим
if (!vars) return false;
// Удаляем классы\стили
$wrap.removeClass(vars.wrap_class);
$menu.removeClass(vars.menu_class)
.css('display', '');
$button.removeClass(vars.button_class);
// Отменяем события
$wrap.off('.dropdown');
$button.off('.dropdown');
$(document).off('.dropdown');
// Удаляю настройки плагина
$wrap.data('dropdown', '');
}
};
// Вызов методов
// Если закрашиваемый метод существует, вызываем его
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
// Если передан объект или ничего, вызываем метод init
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
// Если метода не существует, выдаём ошибку
} else {
$.error('Метод с именем ' + method + ' не существует для jQuery.dropdown');
}
// Функция открытия меню
function open(element) {
var vars = element.data('dropdown');
element
.addClass(vars.open_class)
.trigger('open.dropdown');
// Анимация
switch (vars.animate) {
case 'slide':
element
.children(vars.menu_element)
.stop(true, true)
.slideDown(vars.animate_duraction)
.css('display', 'block');
break;
case 'fade':
element
.children(vars.menu_element)
.stop(true, true)
.fadeIn(vars.animate_duraction)
.css('display', 'block');
break;
default:
element
.children(vars.menu_element)
.css('display', 'block');
break;
}
}
// Функция закрытия меню
function close(element) {
var vars = element.data('dropdown');
element
.removeClass(vars.open_class)
.trigger('close.dropdown');
// Анимация
switch (vars.animate) {
case 'slide':
element
.children(vars.menu_element)
.stop(true, true)
.slideUp(vars.animate_duraction);
break;
case 'fade':
element
.children(vars.menu_element)
.stop(true, true)
.fadeOut(vars.animate_duraction);
break;
default:
element
.children(vars.menu_element)
.css('display', 'none');
break;
}
}
};
}(jQuery));