Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #11 (permalink)  
Старый 05.12.2015, 00:52
Аватар для Алексей Петрович
Аспирант
Отправить личное сообщение для Алексей Петрович Посмотреть профиль Найти все сообщения от Алексей Петрович
 
Регистрация: 29.11.2015
Сообщений: 83

Я доделал свой плагин, прошу оценки, советов по модернизации.
/* ------------------------------------------------------------------

Плагин выпалывающего меню .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));
Ответить с цитированием
  #12 (permalink)  
Старый 05.12.2015, 00:57
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Алексей Петрович,
строка 160
// Если плагин не инициализирован то выходим 
                if (!vars||(vars &&!vars.init)) return false;
Ответить с цитированием
  #13 (permalink)  
Старый 05.12.2015, 01:48
Аватар для Алексей Петрович
Аспирант
Отправить личное сообщение для Алексей Петрович Посмотреть профиль Найти все сообщения от Алексей Петрович
 
Регистрация: 29.11.2015
Сообщений: 83

А что это значит?
Ответить с цитированием
  #14 (permalink)  
Старый 05.12.2015, 02:04
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Сообщение от Алексей Петрович
А что это значит?
data-dropdown отсутствует или есть но непроинициализирована
Ответить с цитированием
  #15 (permalink)  
Старый 05.12.2015, 02:17
Аватар для Алексей Петрович
Аспирант
Отправить личное сообщение для Алексей Петрович Посмотреть профиль Найти все сообщения от Алексей Петрович
 
Регистрация: 29.11.2015
Сообщений: 83

Понятно.

Тут мне пришло в голову сделать, то что не когда не делал))) Управление с клавиатуры.
32 - Пробел
13 - Интер

И тут возникла проблема, я хочу что бы меню открывалось по пробелу или интеру.

$button.on('keypress.dropdown', [32, 13], function () {
   alert('пробел или интер');
});


Но почему то работает только пробел(((
Ответить с цитированием
  #16 (permalink)  
Старый 05.12.2015, 02:30
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Алексей Петрович,
может keyup или keydown тогда?
Ответить с цитированием
  #17 (permalink)  
Старый 05.12.2015, 02:39
Аватар для Алексей Петрович
Аспирант
Отправить личное сообщение для Алексей Петрович Посмотреть профиль Найти все сообщения от Алексей Петрович
 
Регистрация: 29.11.2015
Сообщений: 83

А какая по сути разница?
keypress - Нажатие клавиши, о налог keyup, полное нажатие клавиши
keyup - Поднятие клавиши, когда отпустил клавишу
keydown - Опускание клавиши, нажал но не отпустил

Вот и вся разница, как будто они как то кардинально отличаются в своей работе.

Я тут уже подумал, а как юзер поймет что что-то надо нажимать.
Думаю по фокусу открывать меню, это просто. А вот с закрытием проблема, это как то надо отслеживать что нет дочерних элементов в фокусе.
Ответить с цитированием
  #18 (permalink)  
Старый 05.12.2015, 04:55
Аватар для Алексей Петрович
Аспирант
Отправить личное сообщение для Алексей Петрович Посмотреть профиль Найти все сообщения от Алексей Петрович
 
Регистрация: 29.11.2015
Сообщений: 83

Пришла в голову мысль:
По фокусу открывать меню.
Отслеживать нажатие tab в любом дочернем элементе.
Если tab нажат на последнем focus'абельном элементе, то закрывать меню.

Вообще возможно как то получить список focus'абельных элементов, что бы из него вытащить последний для условия?

На такую мысль я набрел, после того когда вспомнил что плагин не имеет почти не каких привязанностей от вёрстки (Но может чуть-чуть) и следовательно общепринятое управление клавиатурой (пробел открыть, верх низ переключаться по меню) не возможно.
Вот пример: http://jsfiddle.net/gasu9be5/7/, последний пункт меню я туда вообще поиск засунул.
Ответить с цитированием
  #19 (permalink)  
Старый 05.12.2015, 10:13
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Алексей Петрович,
Ответить с цитированием
  #20 (permalink)  
Старый 05.12.2015, 12:09
Аватар для Алексей Петрович
Аспирант
Отправить личное сообщение для Алексей Петрович Посмотреть профиль Найти все сообщения от Алексей Петрович
 
Регистрация: 29.11.2015
Сообщений: 83

Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Не перезаписываемая переменная vars += Орёл Общие вопросы Javascript 3 13.06.2010 16:09