Подтвердить что ты не робот

Сделать работу в списке ul, например select input

Я хочу иметь возможность использовать список ul в качестве элемента выбранной формы для определения стиля.

Я могу заполнить скрытый ввод моим кодом (не включенным в этот jsfiddle), и до сих пор так хорошо. Но теперь я пытаюсь позволить моей ul вести себя как вход выбора при нажатии клавиатуры, или мышь.

В моем предыдущем вопросе у меня были некоторые проблемы с клавиатурным управлением. Теперь они исправлены. Смотрите: Автопрокрутка на клавиатуре стрелка вверх/вниз

Остается проблема в том, что мышь не игнорируется при нажатии кнопок клавиатуры. Это приводит к тому, что "эффект зависания" сначала прослушивает ввод с клавиатуры, но не сразу переходит к мыши и выбирает этот элемент li как выбранный.

Это можно увидеть в моем примере jsfiddle: http://jsfiddle.net/JVDXT/3/

Мой код javascript:

// scrollTo plugin 
  $.fn.scrollTo = function( target, options, callback ){
  if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
  var settings = $.extend({
    scrollTarget  : target,
    offsetTop     : 100,
    duration      : 0,
    easing        : 'linear'
  }, options);
  return this.each(function(){
    var scrollPane = $(this);
    var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
    var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
    scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
      if (typeof callback == 'function') { callback.call(this); }
    });
  });
}


//My code
//The function that is listing the the mouse
jQuery(".btn-group .dropdown-menu li").mouseover(function() {
        console.log('mousie')
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        jQuery(this).addClass('selected');
})  

//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
    if (e.keyCode == 38) { // up
        console.log('keyup pressed');
        var selected = jQuery('.selected');
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        if (selected.prev().length == 0) {
            selected.siblings().last().addClass('selected');
        } else {
            selected.prev().addClass('selected');
            jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
        }
    }
    if (e.keyCode == 40) { // down
        console.log('keydown');
        var selected = jQuery('.selected');
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        if (selected.next().length == 0) {
            selected.siblings().first().addClass('selected');
        } else {
            selected.next().addClass('selected');
            jQuery('.btn-group .dropdown-menu').scrollTo('.selected');
        }
    }
});

Так может ли кто-нибудь научить меня, как igonore мыши при нажатии кнопок клавиатуры, но перечисление на мышь, когда пользователь коснулся ее снова. Как и поле формы ввода по умолчанию.

Update

Здесь новый jsfiddle.

4b9b3361

Ответ 1

Проверьте это:

http://jsfiddle.net/coma/9KvhL/25/

(function($, undefined) {

    $.fn.dropdown = function() {

        var widget = $(this);
        var label = widget.find('span.valueOfButton');
        var list = widget.children('ul');
        var selected;
        var highlighted;

        var select = function(i) {

            selected = $(i);
            label.text(selected.text());

        };

        var highlight = function(i) {

            highlighted = $(i);

            highlighted
            .addClass('selected')
            .siblings('.selected')
            .removeClass('selected');
        };

        var scroll = function(event) {

            list.scrollTo('.selected');

        };

        var hover = function(event) {

            highlight(this);

        };

        var rebind = function(event) {

            bind();

        };

        var bind = function() {

            list.on('mouseover', 'li', hover);
            widget.off('mousemove', rebind);

        };

        var unbind = function() {

            list.off('mouseover', 'li', hover);
            widget.on('mousemove', rebind);

        };

        list.on('click', 'li', function(event) {

            select(this);

        });

        widget.keydown(function(event) {

            unbind();

            switch(event.keyCode) {

                case 38:
                    highlight((highlighted && highlighted.prev().length > 0) ? highlighted.prev() : list.children().last());

                    scroll();
                    break;

                case 40:
                    highlight((highlighted && highlighted.next().length > 0) ? highlighted.next() : list.children().first());

                    scroll();
                    break;

                case 13:
                    if(highlighted) {

                        select(highlighted);

                    }
                    break;

            }

        });

        bind();

    };

    $.fn.scrollTo = function(target, options, callback) {

        if(typeof options === 'function' && arguments.length === 2) {

            callback = options;
            options = target;
        }

        var settings = $.extend({
            scrollTarget  : target,
            offsetTop     : 185,
            duration      : 0,
            easing        : 'linear'
        }, options);

        return this.each(function(i) {

            var scrollPane = $(this);
            var scrollTarget = (typeof settings.scrollTarget === 'number') ? settings.scrollTarget : $(settings.scrollTarget);
            var scrollY = (typeof scrollTarget === 'number') ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop, 10);

            scrollPane.animate({scrollTop: scrollY}, parseInt(settings.duration, 10), settings.easing, function() {

                if (typeof callback === 'function') {

                    callback.call(this);
                }

            });

        });

    };

})(jQuery);

$('div.btn-group').dropdown();

Ключ состоит в том, чтобы отменить привязку мыши и перегруппировку при перемещении мыши.

Я немного отредактировал его, используя функцию закрытия, добавив логику в метод jQuery, называемый выпадающим меню, чтобы вы могли повторно использовать его, используя переключатель вместо связки if и more.

Ну, есть базилии плагинов, чтобы преобразовать выделение в список:

http://ivaynberg.github.io/select2/

http://harvesthq.github.io/chosen/

http://meetselva.github.io/combobox/

, и у меня тоже есть! (готов к сенсорным устройствам с использованием того же трюка, что и http://uniformjs.com)

https://github.com/coma/jquery.select

Но этот вопрос заключается в том, чтобы принять этот HTML-код и заставить его вести себя так, как выбрать, избегая проблемы с зависанием?

Ответ 2

Здесь решение, я использую mousemove, так как это гарантирует, что правый элемент списка будет выбран, как только мышь начнет двигаться снова, при mouseover он только начнет выбирать элемент списка при вводе нового элемент списка:

Возьмите анонимную функцию и дайте ей имя:

function mousemove() {
  console.log('mousie')
  jQuery(".btn-group .dropdown-menu li").removeClass('selected');
  jQuery(this).addClass('selected');
}

Объявите глобальную переменную mousemoved, указывающую, перемещалась ли мышка над документом и устанавливалась она на false, на mousemove над документом, установите его на true и прикрепите функцию mousemove к mousemove событие в элементах списка.

var mousemoved = false;

jQuery(document).mousemove(function() {
  if(!mousemoved) {
    $('.btn-group .dropdown-menu li').mousemove(mousemove);  
    mousemoved = true;    
  }
})  

Как только нажата клавиша (в начале события keydown), используйте метод jQuery .off(), чтобы удалить mousemove в элементе списка, если он присутствует, и установите mousemoved в false, чтобы гарантировать, что событие mousemove не будет прикреплено снова, пока мышь не будет перемещена снова.

jQuery(".btn-group").keydown(function(e) {

  $('.btn-group .dropdown-menu li').off('mousemove');
  mousemoved = false; 
  ... // Some more of your code

Здесь jsFiddle.

Ответ 3

Я попытался решить вашу проблему, запретив автопрокрутку, добавив tabindex в li, установив фокус на активный и используя флаг для подавления мыши.

Исправлена ​​скрипта: http://jsfiddle.net/8nKJT/ [исправлена ​​проблема в Chrome]

http://jsfiddle.net/RDSEt/

Проблема связана с автоматическим scroll, который запускается на keydown, который снова запускает mouseenter помещает выбор li.

Примечание: Различия с другими подходами (ответы здесь) Я заметил, что он прокручивает каждое нажатие клавиши вместо прокрутки только после достижения верхнего или нижнего уровня (нормальное поведение). Вы почувствуете разницу, когда вы проверяете демонстрацию бок о бок.

Ниже приведен список описаний изменений и небольшая демонстрация, чтобы объяснить, как она была исправлена,

  • Предотвращенная автоматическая прокрутка, которая запускается при нажатии стрелки вверх/вниз, используя e.preventDefault() http://jsfiddle.net/TRkAb/ [нажмите вверх/вниз на ul li], попробуйте сделать то же самое на http://jsfiddle.net/TRkAb/1/ [Больше не прокручивать]
  • Добавлен флаг на keydown, чтобы подавить мыши на клавиатуре, этот флаг reset onmousemove
  • Добавлен tabindex в li, который позволит вам установить фокус с помощью функции .focus. [Дополнительная информация: fooobar.com/questions/150364/...]
  • Вызов .focus будет автоматически прокручиваться до нужного места. (нет необходимости в плагине scrollTo) http://jsfiddle.net/39h3J/ - [Проверить, как он прокручивается до ли, который находится в фокусе)

Проверьте изменения демо и кода (добавлено несколько улучшений) и дайте мне знать.

Также благодаря вашему вопросу я заметил эту проблему и кучу других проблем в одном из плагинов, которые я написал.

Я написал плагин несколько месяцев назад, чтобы фильтровать параметры, а также действовать точно так же, как выпадающее меню.

DEMO: http://jsfiddle.net/nxmBQ/ [изменить filterType на '', чтобы отключить фильтрацию]

Исходная страница плагина http://meetselva.github.io/combobox/

.. больше

Ответ 4

Вы можете использовать глобальное значение для игнорирования события mouseover, если недавно было добавлено квитирование в виджетах. Например:

var last_key_event = 0;

jQuery(".btn-group .dropdown-menu li").mouseover(function() {
    if ((new Date).getTime() > last_key_event + 1000) {
        console.log('mousie')
        jQuery(".btn-group .dropdown-menu li").removeClass('selected');
        jQuery(this).addClass('selected');
    }
});

Затем обработчик keydown может установить, когда он был обработан, чтобы избежать взаимодействия с мышью:

//What to do when the keyboard is pressed
jQuery(".btn-group").keydown(function(e) {
    last_key_event = (new Date).getTime();
    ...
});

Может быть, имеет смысл иметь переменную last_key_event для каждого виджета, а не глобальную.

Ответ 5

Вы можете попробовать это решение. Он игнорирует событие mousemove, если координаты не изменились (с момента последнего события mousemove)

//The function that is listing the the mouse
var lastOffsets = "";

jQuery(".btn-group .dropdown-menu li").mouseover(function(e) {
        var curOffsets = e.clientX+":"+e.clientY;
        if(curOffsets == lastOffsets) {
           // mouse did not really move
            return false;
        }

        lastOffsets = curOffsets;

        ///// rest of your code
}

Обновлен скрипт, чтобы убедиться, что это было после: http://jsfiddle.net/pdW75/1/

Ответ 6

Подход. Разумное решение должно имитировать поведение других элементов интерфейса, которые служат аналогичной цели. Во всех проверенных системах (Windows, Linux, основные браузеры) выпадающие окна ведут себя следующим образом:

Мышь над предметом подсвечивает его. Нажатие клавиш со стрелками изменяет выбранный элемент и выполняет прокрутку. Перемещение мыши выбирает элемент под ним. Если выбор пуст, нажатие down выбирает первый элемент. Нажатие up выбирает последний элемент.

Решение Этот код иллюстрирует мой подход к имитации описанного поведения. Это классно, попробуйте...

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

  • Сохранение состояния последнего метода ввода. Если последний выбор использовался с клавиатуры, зависание над элементом не будет выбрано, только щелчок будет
  • игнорирование события mouseover, если координаты не изменились на заданное расстояние, например. 10 пикселей
  • игнорирование mouseover, если пользователь когда-либо использовал клавиатуру

Однако, по крайней мере, для приложения, доступного для публики, всегда лучше придерживаться установленных шаблонов пользовательского интерфейса.

Ответ 7

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

Вы можете решить эту проблему и сохранить всю функциональность без каких-либо сложных условных действий или удаления обработчиков событий.

Просто измените обработчик событий mouseover как обработчик события mousemove. Таким образом, прослушивается любая навигация и выбор клавиатуры и позиция мыши игнорируется в любое время, когда пользователь использует клавиатуру для выбора. И в любое время, когда мышь используется для выбора, тогда мышь прослушивается.

Это звучит тривиально, но похоже, что ваш JS Fiddle ведет себя отлично и без какого-либо противоречивого поведения между мышью и клавиатурой. Вот так:

//The function that is listening to the mouse
jQuery(".btn-group .dropdown-menu li").mousemove...

(ваш код остается неизменным, только заменяя mouseover на mousemove)