【问题标题】:Capture keypress to filter elements捕获按键以过滤元素
【发布时间】:2011-08-21 19:05:48
【问题描述】:

我正在使用 jQuery 创建一个 <select> 替换,用 div 和链接替换它。

现在我想在打开新选择的情况下开始输入内容时对其进行过滤。

就像 Google Translate 在语言选择器上所做的那样。

你有什么建议吗?

我从以下开始:

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

但我只捕获单个键,而不是整个键入的字符串。


重要:

  • 我没有<input /> 来检测它上面的keypress 或keyup 事件
  • 我不想创建这个<input />,因为我只想在“新选择”中使用<div> 和<a>
  • 最近我需要在打开的选择上导航,使用箭头键 + Enter 以使用我的键盘选择选项

【问题讨论】:

  • FWIW,你应该看看oninput 事件,它更适合检测文本输入。 whattheheadsaid.com/2010/09/…
  • @Andy E - 这仅适用于<input />?
  • @TiuTalk:它适用于接受输入的元素,例如<input> 和<textarea>。大多数开发人员设计了一个输入元素,您可以在其中键入并将事件附加到该元素。
  • @Andy E:所以你建议我创建一个<input /> 来接收按键?
  • 我有一些工作(见我的回答),希望这就是你所追求的。

标签: javascript jquery string detection keypress


【解决方案1】:

如果您不想使用隐藏的下拉菜单(我仍然强烈建议您这样做),我建议您遵循以下建议:

通过http://jsfiddle.net/aWE8b/

的简单语言下拉列表查看完整的工作演示

演示包含:

  • 自定义下拉菜单
  • 支持的键:
    • 退格键
    • 输入
    • 逃跑
    • 左,上
    • 右,下
  • 2 种模式:
    • 过滤器:删除不匹配的项目
    • 选择:突出显示第一个匹配项

【讨论】:

    【解决方案2】:

    按照你的要求怎么做

    每次在文档上触发 keypress 事件时,将输入的字符记录在变量中(可从全局范围或闭包中访问)或页面上的元素中(您可以选择如果您不希望用户看到它,请使用 display: hidden;)。

    然后,遍历下拉列表中的元素并隐藏那些不包含/以您从单个击键构建的字符串开头的元素。

    实际推荐的内容

    使用输入元素来包含用户键入的击键,并让用户看到该元素。

    为什么?

    因为这是用户已经熟悉的交互行为。如果您不使用输入元素,则会打开几个已使用输入元素解决的新问题:

    1. 用户如何知道他们可以通过输入来过滤列表? 输入元素是对用户的明确声明:“您应该在此处输入!”
    2. 当用户按下多个键时,他们如何知道要过滤哪个字符串? 当我在那个谷歌翻译界面中快速输入“hu”时,我会选择“匈牙利语”预计。但是,当我慢慢打字时会发生什么?如果速度足够慢,则选择“Hatian Creole”,然后选择“Ukranian”。
    3. 如果我输入错误并想重新开始怎么办? 是否有一个按钮可以清除它?我需要等待多长时间才能让过滤器自行清除?

    您可以当然创建一个新的界面元素来解决所有这些问题,如果这是你的目标,那就去做吧,但这类事情已经存在标准。

    首先,前面提到的autocomplete 小部件非常方便,而且非常灵活。

    【讨论】:

      【解决方案3】:

      你不想使用输入的原因是什么,如果 JS 不可用,你可以优雅地退回到选择吗?如果是这样,这可能会满足您的要求,尽管我最终在其中输入了一个输入,但我已将 select 作为基础并从那里获取值。

      根据 Neal 的回答,我认为自动完成功能与您需要的非常相似,但如果您想以不同的方式显示结果,我在显示过滤结果的同一示例中提供了第二种方法。

      此处的完整示例版本: 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();
      

      【讨论】:

        【解决方案4】:

        您可以通过“侦听”窗口上按下的内容,然后检测按下的特定字母/字符串,搜索项目列表,如果发现它更改其 css 属性或添加新的“选定”类来实现这一点ie (demo => http://jsfiddle.net/steweb/mC6tn/ ..try press any :) and add 在找到东西后按左或右 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
        });
        

        EDIT添加了左/右/输入键处理

        $(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'));
            }
        });
        

        【讨论】:

        • 你可以使用 String.fromCharCode(e.keyCode) 如果你想捕获它们,而不需要每个 if 语句。
        • 很好的解决方案!我也建议处理BackSpace 键!很多人(包括我)在写一些单词并出现错误时会自动按退格键来纠正错字,即使没有可见的 也是如此。在这种情况下,浏览器会转到上一页 :)
        • 我不喜欢这个解决方案,因为它不是用户所期望的。当在页面上的任意位置按下键时,为什么要更改选择?退格键呢?如果按下它,您现在有 2 个选项(使用此解决方案):浏览器触发 back 操作,或者您捕获并阻止此行为 -> 这会破坏浏览器的默认行为,因此很糟糕。
        • 这是实现类似于谷歌翻译功能的起点:) ..如果你看那里,你可以按页面上的任何地方..然后,这里和那里的退格键都没有实现。干杯。附:你将如何改进这一点?我们在这里帮助和学习:)
        • 我认为后退按钮也应该固定在谷歌的网站上(如果焦点在自定义下拉菜单上,则不应返回)。而且,您的示例中应该有一个下拉按钮。在页面中的某处键入会更改下拉列表的选择似乎不合逻辑。但你是对的,这是一个开始使用它的例子:)
        【解决方案5】:

        我尝试做的是:

        1) 获取按键(仅 0-9、a-z 和空格)并将其保存在 div 中 2) 创建了一个 LI 列表(您可以使用带有 a 元素的 div,也可以) 3) 使用正在保存的文本查找 LI 项 4)添加上/右下/左箭头以获取列表中的下一个/上一个项目

        现在它保留列表中的所有项目,如果需要,您也可以隐藏它们。这只是一个插图。

        //EDIT:

        这是一个初学者设置:http://www.pendemo.nl/keyinputtest.html 在 Firefox 中,不会自动选择正文,这导致您需要在检测到第二个输入之前再次单击正文/网页。在 Chrome 中,它会检测到一个接一个地按下的键。

        //EDIT2:

        在 Firefox 中工作。文本现在保存在 div 中(您可以键入所需的字符串并看到它被放置在正文中)。

        //EDIT3:

        添加了包含一些项目的 UL 列表。键入一些文本将使用与键入的字符串匹配的项目过滤此列表。

        //EDIT4:

        仅使用 a-z 和空格进行搜索。仍在寻找如何找到退格键的方法。由于 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 代码以满足您的需要。

        【讨论】:

          【解决方案6】:

          我用&lt;div&gt; 标签创建了我自己的&lt;select&gt; 版本,在这里查看。如果我理解正确,这就是你想要的。

          http://jsfiddle.net/myTPC/

          它还支持退格(至少在 Firefox 中)。

          【讨论】:

            【解决方案7】:

            这个呢:

            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) {
                    ....    ....
                    ....    ....
                }
            
            });
            

            【讨论】:

              【解决方案8】:

              你可以试试这样的:

              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
              }

              这将捕获整个字符串 onTimeout。稍微调整一下超时时间,让它变得干净整洁!

              【讨论】:

              • 我没有 来检测其上的按键或按键事件
              • 您只是检查用户是否在页面的任何位置输入内容?
              【解决方案9】:

              您可以尝试使用 jQuery UI 的autocomplete

              【讨论】:

              • 这不是我想要的...我真的很想替换 &lt;select&gt; 元素
              • 我没有 来检测其上的按键或按键事件
              • @TiuTalk:如何在不使用某种&lt;input&gt; 元素的情况下替换&lt;select&gt; 元素?对我来说,自动完成功能似乎完全符合您的要求......
              • @TiuTalk:@Neal 和@Denis 是对的,jQuery-UI 自动完成可以替换一个&lt;select&gt; 元素:jqueryui.com/demos/autocomplete/#combobox
              猜你喜欢
              • 2011-03-10
              • 1970-01-01
              • 1970-01-01
              • 2012-02-28
              • 2016-09-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多