Сделать работу в списке 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.
Ответы
Ответ 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)