【问题标题】:Filtering a list as you type with jQuery使用 jQuery 在键入时过滤列表
【发布时间】:2009-11-20 17:25:37
【问题描述】:

我计划使用简单的数据库查询来创建我的 Web 应用程序用户的无序列表,但随后计划让人们通过在文本输入中输入他们正在寻找的人的姓名来过滤此列表。

我希望使用 jQuery 将输入框中的字符串与列表项中的任何一个进行匹配,然后隐藏其他项,可能是通过将新类动态应用于包含匹配字符串的类,然后隐藏所有其他不包含该类的。

有谁知道这样做的好方法吗?

【问题讨论】:

  • 当你在一个项目中多次需要这样的东西时,你应该看看 AngularJS,它几乎不需要代码就可以轻松做到这一点:)
  • 我现在几乎只使用 Angular,这是六年前发布的。哇...现在我感觉自己老了。

标签: jquery ajax


【解决方案1】:

假设您的ul 有一个idtheList,以下是一种方法。

<input type="text" onkeyup="filter(this)" />

<script language="javascript" type="text/javascript">
    function filter(element) {
        var value = $(element).val();

        $("#theList > li").each(function() {
            if ($(this).text().search(value) > -1) {
                $(this).show();
            }
            else {
                $(this).hide();
            }
        });
    }
</script>

如果您不希望使用区分大小写的过滤器,请在这些行中添加 .toLowerCase(),如下所示:

var value = $(element).val().toLowerCase();
if ($(this).text().toLowerCase().search(value) > -1)

或者,对于基于 Marek Tihkan 发布的更简洁的版本,您可以将 each() 循环替换为以下内容。不确定这会表现得更好还是更差。

$('#theList > li:not(:contains(' + value + '))').hide(); 
$('#theList > li:contains(' + value + ')').show();

【讨论】:

  • hide() 和 show() 工作但不与输入值比较
  • 如果我有 php while 循环,则此代码在静态内容上运行,然后它不工作
  • 噗!我曾经完成过的最简单的 javascript 实现。谢谢。
  • 带有“each”的方法更容易适应忽略大写和重音字符。
  • 您自己的方法在不需要区分大小写的情况下效果更好。它应该类似于:var value = $(element).val().toLowerCase();$(this).text().toLowerCase().search(value) &gt; -1
  • 【解决方案2】:

    如果输入文本为空,Nikolas 给出的解决方案结合 Marek 的解决方案会引发错误。
    下面的解决方案纠正了这个问题,适用于被“a”标签包围的列表。

    该功能还设计用于过滤首字母大写的单词(例如名称)。因此过滤是有序的。如果您输入“An”或“an”,那么您将获得列表中以这些字母开头的所有元素(例如 Anthony 将匹配但 Fanny 不匹配)。

    function filter (element,what) {
        var value = $(element).val();
        value = value.toLowerCase().replace(/\b[a-z]/g, function(letter) {
            return letter.toUpperCase();
        });
    
        if (value == '') {
            $(what+' > a > li').show();
        }
        else {
            $(what + ' > a > li:not(:contains(' + value + '))').hide();
            $(what + ' > a > li:contains(' + value + ')').show();
        }
    };
    

    以下是与脚本一起使用的示例 HTML 代码:

    <input type="text" onkeyup="filter(this,'theList')" />
    <ul id="theList">
        <li><a href="">Tyrone Schlecht</a></li>
        <li><a href="">Javier Ress</a></li>
        <li><a href="">Carlene Tomes</a></li>
        <li><a href="">Neil Aigner</a></li>
        <li><a href="">Nita Schreffler</a></li>
        <li><a href="">Clinton Knuckles</a></li>
        <li><a href="">Eve Kellett</a></li>
        <li><a href="">Jamie Kaspar</a></li>
        <li><a href="">Emilia Hooton</a></li>
        <li><a href="">Kenya Sidney</a></li>
    </ul>
    

    【讨论】:

    • 将锚 (a) 标签作为 UL 的子标签是无效的 HTML。
    • 您可能需要更新您的 jQuery 代码以匹配您的 HTML 编辑。
    【解决方案3】:

    我通过迭代所有这些来做到这一点,并隐藏那些不匹配的女巫并显示那些匹配的。

    $('li').hide(); 
    $('li:contains(' + needle + ')').show();
    

    【讨论】:

      【解决方案4】:

      您可以使用由 John Resig 从 php 移植到 jQuery 的 LiveQuery

      注意:它依赖于Quicksilver's score method in PHP方法,该方法已被LiquidMetal.scorejoshaven's string.score移植到JavaScript

      使用示例

      $("#text_box_selector").liveUpdate("#list_selector");
      

      注意#list_selector 必须找到包含 li 元素的元素

      插件+排序+现场演示

      // https://github.com/joshaven/string_score
      String.prototype.score = function (word, fuzziness) {
        'use strict';
      
        // If the string is equal to the word, perfect match.
        if (this === word) { return 1; }
      
        //if it's not a perfect match and is empty return 0
        if (word === "") { return 0; }
      
        var runningScore = 0,
            charScore,
            finalScore,
            string = this,
            lString = string.toLowerCase(),
            strLength = string.length,
            lWord = word.toLowerCase(),
            wordLength = word.length,
            idxOf,
            startAt = 0,
            fuzzies = 1,
            fuzzyFactor,
            i;
      
        // Cache fuzzyFactor for speed increase
        if (fuzziness) { fuzzyFactor = 1 - fuzziness; }
      
        // Walk through word and add up scores.
        // Code duplication occurs to prevent checking fuzziness inside for loop
        if (fuzziness) {
          for (i = 0; i < wordLength; i+=1) {
      
            // Find next first case-insensitive match of a character.
            idxOf = lString.indexOf(lWord[i], startAt);
      
            if (idxOf === -1) {
              fuzzies += fuzzyFactor;
            } else {
              if (startAt === idxOf) {
                // Consecutive letter & start-of-string Bonus
                charScore = 0.7;
              } else {
                charScore = 0.1;
      
                // Acronym Bonus
                // Weighing Logic: Typing the first character of an acronym is as if you
                // preceded it with two perfect character matches.
                if (string[idxOf - 1] === ' ') { charScore += 0.8; }
              }
      
              // Same case bonus.
              if (string[idxOf] === word[i]) { charScore += 0.1; }
      
              // Update scores and startAt position for next round of indexOf
              runningScore += charScore;
              startAt = idxOf + 1;
            }
          }
        } else {
          for (i = 0; i < wordLength; i+=1) {
            idxOf = lString.indexOf(lWord[i], startAt);
            if (-1 === idxOf) { return 0; }
      
            if (startAt === idxOf) {
              charScore = 0.7;
            } else {
              charScore = 0.1;
              if (string[idxOf - 1] === ' ') { charScore += 0.8; }
            }
            if (string[idxOf] === word[i]) { charScore += 0.1; }
            runningScore += charScore;
            startAt = idxOf + 1;
          }
        }
      
        // Reduce penalty for longer strings.
        finalScore = 0.5 * (runningScore / strLength    + runningScore / wordLength) / fuzzies;
      
        if ((lWord[0] === lString[0]) && (finalScore < 0.85)) {
          finalScore += 0.15;
        }
      
        return finalScore;
      };
      
      // http://ejohn.org/apps/livesearch/jquery.livesearch.js
      jQuery.fn.liveUpdate = function(list) {
        list = jQuery(list);
      
        if (list.length) {
          var rows = list.children('li'),
            cache = rows.map(function() {
              return this.innerHTML.toLowerCase();
            });
      
          this
            .keyup(filter).keyup()
            .parents('form').submit(function() {
              return false;
            });
        }
      
        return this;
      
        function filter() {
          var term = jQuery.trim(jQuery(this).val().toLowerCase()),
            scores = [];
      
          if (!term) {
            rows.show();
          } else {
            rows.hide();
      
            cache.each(function(i) {
              var score = this.score(term);
              if (score > 0) {
                scores.push([score, i]);
              }
            });
      
            jQuery.each(scores.sort(function(a, b) {
              return b[0] - a[0];
            }), function() {
              jQuery(rows[this[1]]).show();
            });
          }
        }
      };
      
      $("#search").liveUpdate("#colors");
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
      
      <input type="text" id="search"><br/>
      
      <ul id="colors">
        <li>Cat Book</li>
        <li>Dog Basket</li>
        <li>Bear Cub</li>
        <li>Car Door</li>
        <li>Another option</li>
        <li>Another Animal</li>
      </ul>

      【讨论】:

        【解决方案5】:
        // Just a shorter version
        $('ul>li').hide().has(':contains(' + needle + ')').show();
        
        // case insensitive searching with animation
        $("ul>li").slideUp().filter( function() {
             return $(this).text().toLowerCase().indexOf(needle) > -1
        }).stop(true).fadeIn();
        

        【讨论】:

          【解决方案6】:

          this W3 example 中汲取主要灵感,我开发了一个可能的替代方案和compact solution

          在链接的示例中可以看到 3 个不同的选项:

          • 仅过滤 UL 项目
          • 过滤任何项目
          • 使用 css 动画效果过滤任何项目

          最简单的 JS 代码如下,借助 $("#anyItemList *") 选择器,它可以简单地过滤任何类型的元素:

            $("#anyItemListInputFilter").on("keyup", function() {
              var value = $(this).val().toLowerCase();
              $("#anyItemList *").filter(function() {
                  let item = $(this).text().toLowerCase().indexOf(value) > -1;
                $(this).toggle(item);
              });
            });
          

          如果所需的过滤仅适用于 UL 列表,则该选择器可以更改为 $("#ulList li")(如示例)

          如果你还想添加css动画效果,有一些限制:

          • 需要在px 中预定义max-height(如果设置足够高,可能影响不大)
          • overflow-y:hidden;

          所以我不得不声明:

          #anyItemAnimatedList * {
            transition:all 0.5s ease;
            opacity:1;
            max-height:500px;
           overflow-y:hidden;
          }
          
          #anyItemAnimatedList ul {
            list-style-position:inside;
          }
          
          #anyItemAnimatedList .hidden {
            max-height:0;
            opacity:0;
            border:0;
          }
          

          隐藏效果是通过opacitymax-height的css转换组合而成的,border:0是覆盖button标签默认浏览器样式所必需的。

          此外,在OLUL 列表的情况下,必须设置list-style-position:inside;,因为Firefox 和Chrome 共享一个奇怪的默认行为,在默认list-style-position:outside 的情况下隐藏项目符号。

          对于 Firefox,这是自 2003 年以来的known bug!!!还有 Chrome has the same behaviour

          【讨论】:

            猜你喜欢
            相关资源
            最近更新 更多
            热门标签