Захватить нажатие на элементы фильтра - PullRequest
5 голосов
/ 09 мая 2011

Я создаю замену <select>, используя jQuery для замены на div и ссылки.

Теперь я хочу отфильтровать , когда я начну что-то печатать с новым открытым выбором.

Мне нравится Переводчик Google делает выбор языка.

У вас есть какой-нибудь совет, как мне поступить?

Я начал что-то с:

$(document).bind('keypress', function(event) {
   //...
});

Но я фиксирую только отдельные ключи, а не всю напечатанную строку.


Важно:

  • У меня нет <input /> для обнаружения событий keypress или keyup на нем
  • Я предпочитаю не создавать <input />, так как я хочу использовать только <div> и <a> на "новом выборе"
  • В последнее время мне нужно будет перемещаться по открытому выбору с помощью клавиш со стрелками + ввод, чтобы выбрать опцию с моей клавиатурой

Ответы [ 9 ]

2 голосов
/ 14 мая 2011

Этого можно добиться, «прослушав» то, что нажимается в окне, а затем обнаружив конкретную нажатую букву / строку, выполнив поиск по списку элементов и, если вы обнаружите, измените его свойства CSS или добавьте новый «выбранный» класс то есть (demo => http://jsfiddle.net/steweb/mC6tn/ ..try нажав что угодно :) и добавлено после того, как что-то найдено, нажмите левую или правую btns или введите):

JS : (предположим, что каждый элемент, в котором вы хотите найти что-то и выбрать его, имеет класс 'elem')

var whatYouAreSearching = $('<div class="searching-string"></div>'); //just to see what string you're typing
$(document.body).append(whatYouAreSearching);

function search(what){
    what = what.toLowerCase();
    $('.elem').removeClass('selected'); //reset everything
    $.each($('.elem'),function(index,el){
        if($(el).html().toLowerCase().indexOf(what) > -1){
            $(el).addClass('selected');
            return false; //found, 'break' the each loop
        }
    });
}

var letterPressed = [];
var timeOutResetLetters = null;

$(window).keypress(function(e) {
    clearTimeout(timeOutResetLetters); //clear timeout, important!
    timeOutResetLetters = setTimeout(function(){ //if 500 ms of inactivity, reset array of letters pressed and searching string
        letterPressed = []; 
        whatYouAreSearching.html('');
    },500);
    letterPressed.push(String.fromCharCode(e.keyCode)); //look at the comment, thanks Niclas Sahlin 
    whatYouAreSearching.html(letterPressed.join('')); //show string
    search(letterPressed.join('')); //and search string by 'joining' characters array
});

РЕДАКТИРОВАТЬ добавлена ​​обработка клавиш влево / вправо / ввод

$(window).keydown(function(e){ //left right handling
    var currSelected = $('.elem.selected');

    if(e.keyCode == "37"){ //left, select prev
        if(currSelected.prev() && currSelected.prev().hasClass('elem')){
            currSelected.prev().addClass('selected');
            currSelected.removeClass('selected');   
        }
    }else if(e.keyCode == "39"){ //right, select next
        if(currSelected.next() && currSelected.next().hasClass('elem')){
            currSelected.next().addClass('selected');
            currSelected.removeClass('selected');   
        }
    }else if(e.keyCode == "13"){ //enter
       $('.entered').remove();
       $(document.body).append(currSelected.clone().addClass('entered'));
    }
});
2 голосов
/ 09 мая 2011

Вы можете попробовать использовать JQuery UI автозаполнение

1 голос
/ 18 мая 2011

Как сделать то, что вы спросили

Каждый раз, когда событие нажатия клавиши запускается в документе, сохраняйте запись введенного символа либо в переменной (доступной из глобальной области видимости, либо в закрытии), либо в элементе на странице (вы можете выбрать использовать display: hidden;, если вы не хотите, чтобы это было видно пользователю).

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

Что на самом деле рекомендуется

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

Почему?

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

  1. Как пользователь узнает, что он может печатать, чтобы отфильтровать список? Входные элементы являются четким объявлением для пользователя: «Вы должны печатать здесь!»
  2. Как пользователь узнает, какая строка будет отфильтрована, когда он нажмет более одной клавиши? Когда я быстро наберу 'hu' в этом интерфейсе Google Translate, будет выбран 'Венгерский', так как Я бы ожидал. Однако что происходит, когда я набираю текст медленно? Если он достаточно медленный, выбирается «Хатианский креольский», а затем «Украинский».
  3. Что, если я что-то напишу и захочу начать все сначала? Есть ли кнопка, чтобы нажать ее, чтобы убрать? Как долго мне нужно ждать, пока фильтр сам очистится?

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

Например, ранее упомянутый виджет autocomplete действительно удобен и очень гибок.

0 голосов
/ 18 мая 2011

Если вы не хотите использовать скрытый раскрывающийся список (который я по-прежнему настоятельно рекомендую), я предлагаю следующее:

  • Сделайте DIV фокусируемым

    Это работает благодаря обходному пути "tabindex", найденному на http://snook.ca/archives/accessibility_and_usability/elements_focusable_with_tabindex

  • Захват только нажатий клавиш в вашем пользовательском раскрывающемся списке, НЕ только на всем документе.Во-первых, это необычное поведение.Во-вторых, как бы вы справились с более чем одним пользовательским выпадающим списком?
  • Сохраните строку фильтра через данные jQuery контейнер

Проверьте полную работудемо с простым языковым выпадающим списком http://jsfiddle.net/aWE8b/

Демо содержит:

  • Custom Dropdown
  • Поддерживаемые клавиши:
    • Backspace
    • Ввод
    • Выход
    • Влево, вверх
    • Вправо, вниз
  • 2 Режимы:
    • Фильтр: удалить несопоставленные элементы
    • Выбрать: выделить первый соответствующий элемент
0 голосов
/ 14 мая 2011

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

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

Полная версия примера здесь: http://jsfiddle.net/R7APm/9/

Вот JS от него:

$opts = $('option', '#myselect');

//Grab the text from the select (could use option values instead with .val()
var values = [];
$.each($opts, function(i, opt) {
    values.push($(opt).text());
});

$div = $('<div/>');

//Autocomplete version
$input = $('<input/>').autocomplete({
    source: values
});

//Filter in div version
$wordlist = $('<div id="wordlist"/>');
$wordlist.text(values.join(", "));

$input.keyup(function() {
    matches = $.grep(values, function(el, i) {
        if (el.toLowerCase().indexOf($input.val().toLowerCase()) >= 0) {
            return true;
        } else {
            return false;
        }
    });

    $wordlist.text(matches.join(", "));
});

//Add new elements to wrapper div
$div.append($input);
$div.append($wordlist);

//Replace select with wrapper div
$('#replaceme').replaceWith($div);
$input.focus();
0 голосов
/ 14 мая 2011

Я пытался сделать следующее:

1) получить нажатие клавиш (только 0-9, az и пробел) и сохранить это внутри div 2) создать список LI (вы можете использоватьdiv с a-elements, это тоже хорошо) 3) найти элементы LI с сохраняемым текстом 4) добавить стрелки вверх / вправо вниз / влево, чтобы получить следующий / предыдущий элемент в списке

А покасохраняет все элементы в списке, вы можете скрыть их, если хотите.Это просто иллюстрация.

// EDIT:

Вот начальная настройка: http://www.pendemo.nl/keyinputtest.html В Firefox тело не выбирается автоматически, поэтому вам нужно щелкнуть тело/ веб-страницу еще раз, прежде чем второй вход обнаруживается.В Chrome он обнаруживает нажатие клавиш после друг друга.

// EDIT2:

Работа в Firefox.Текст теперь сохраняется внутри div (вы можете ввести нужную строку и увидеть, как она помещается в тело).

// EDIT3:

Добавлен список UL с некоторыми элементами,ввод некоторого текста отфильтрует этот список с элементами, соответствующими набранной строке.

// EDIT4:

Для поиска используются только az и пробел.Все еще ищу способ найти клавишу возврата.Так как Chrome добавляет «history.go-1» по умолчанию.Firefox, однако, замечает клавишу возврата.event.preventDefault () ничего не меняет в Chrome.

// EDIT5:

Добавлена ​​стрелка вверх + вправо для выбора следующего массива, а влево + вниз для выбора предыдущего элемента.

// EDIT6:

При использовании клавиши ввода текущее значение является предупреждением.Конечно, сценарии останавливается после предупреждения.Но, как вы можете видеть, значение доступно для вас.

Вот код, который я придумал до сих пор:

var typed_string = '';

$(document).ready(function() { $('#typedtext').select(); });

$(document).bind('keypress', function(event) {
    event.preventDefault();

    if((event.which > 47 && event.which < 58) || (event.which > 96 && event.which < 123) || event.which == 32) {
        typed_string = typed_string + String.fromCharCode(event.which);
        $('#typedtext').html(typed_string);

        $('#testlist li').css('background-color', '#ffffff');
        $('#testlist li:contains('+typed_string+')').css('background-color', 'green').first().addClass('selected').css('background-color', 'red');

        $('#typedtext').select();
    }

    if(event.which == 13) {
        alert('Selected item: ' + $('.selected').html());
        $('#typedtext').select();
    }
});

$(document).keyup(function(event) {
    event.preventDefault();
    if(event.which == 38 || event.which == 37) {
        $('#testlist li').css('background-color', '#ffffff');
        $('#testlist li:contains('+typed_string+')').css('background-color', 'green');
        $('.selected').removeClass('selected').prev().css('background-color', 'red').addClass('selected');
    }

    if(event.which == 39 || event.which == 40) {
        $('#testlist li').css('background-color', '#ffffff');
        $('#testlist li:contains('+typed_string+')').css('background-color', 'green');
        $('.selected').removeClass('selected').next().css('background-color', 'red').addClass('selected');
    }
});

function clearInput() {
    typed_string = '';  
}

И я использую этот HTML:

Press any key to save text.<br /><br />
<div id="typedtext" style="border: 1px solid #09F; padding: 5px;"></div>

<br /><br />
Let's test to filter some items from the li. (use up/down or left/right keys to select next item)
<ul id="testlist">
    <li>item</li>
    <li>test</li>
    <li>more test</li>
    <li>another item</li>
    <li>test item</li>
    <li>more item</li>
    <li>foo</li>
    <li>foo bar</li>
    <li>bar</li>
    <li>more foo</li>
</ul>

Я думаю, что вам достаточно легко изменить HTML-код в соответствии с вашими потребностями.

0 голосов
/ 13 мая 2011

Я создал свою собственную версию <select> с тегами <div>, проверьте это здесь .. Если я вас правильно понимаю, это то, что вы хотите ..

http://jsfiddle.net/myTPC/

Он также поддерживает возврат (по крайней мере, в Firefox).

0 голосов
/ 13 мая 2011

Что по этому поводу:

var word='';
$(document).bind('keypress', function(event) {
    //UPDATE word ACCORDING TO THE CHAR, LIKE:
    if (event.charCode >=48 && event.charCode <=57) {
        ....    ....
        ....    ....
    }
    //OR
    switch(event.charCode) {
        ....    ....
        ....    ....
    }

});
0 голосов
/ 09 мая 2011

вы можете попробовать что-то вроде этого:

var _interval;

$("#textarea/field_id").bind('keypress', function(event) {
   clearTimeout(_interval);
   _interval = setTimeout(onTimeout, 1000);
});

function onTimeout(){
   var words = $("#textarea/field_id").val().split(' ');//do what you want with the string in the field
}

Это будет захватывать всю строку по времени. Немного поиграйте с таймаутом, чтобы он был красивым и чистым!

...