使用 jQuery 键入时过滤列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1772035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 12:06:36  来源:igfitidea点击:

Filtering a list as you type with jQuery

jqueryajax

提问by Dan Matthews

I was planning to create an unordered list of users of my web application using a simple database query, but then was planning to let people filter this list down by typing the person's name they're looking for into a text input.

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

I was hoping to use jQuery to match the string in the input box to any inside one of the list items, then hide the other ones, maybe by applying a new class dynamically to the ones that contain the matching string, and hiding all others that don't contain that class.

我希望使用 jQuery 将输入框中的字符串与列表项中的任何一个匹配,然后隐藏其他的,也许通过动态地将一个新类应用到包含匹配字符串的那些,并隐藏所有其他的不包含该类。

Does anyone know of a good way to do this?

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

回答by Nikolas Stephan

Assuming that your ulhas an idof theList, the following would be one way of doing it.

假设您ul有一个idof theList,以下将是一种方法。

<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>

Alternatively for a more concise version based on what Marek Tihkan posted you could replace the each() loop with the following. Not sure whether this would perform better or worse.

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

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

回答by efx

The solution given by Nikolas combined with the one of Marek rise an error if the input text is empty.
The solution below corrects that and works for lists surrounded by an 'a' tag.

The function is also designed to filter elements with words having their first letter uppercased (as for example with names). The filtering is thus ordered. If you type 'An' or 'an' then you will get all the elements in the list starting by those letters (e.g. Anthony will match but Fanny no).

如果输入文本为空,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();
    }
};

Below is a sample HTML code that works with the script:

下面是与脚本一起使用的示例 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>

回答by Marek Tihkan

I did it by iterating all of them and hide those witch didn't match and showed those which matched.

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

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

回答by David Murdoch

You can use LiveQuerywhich was ported from php to jQuery by John Resig.

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

Note: It has a dependency on Quicksilver's scoremethod in PHPmethod, which has been ported to JavaScript by LiquidMetal.scoreand joshaven's string.score

注意:它依赖于 PHP方法中的Quicksilverscore方法,该方法已由joshavenLiquidMetal.scorejoshaven移植到 JavaScriptstring.score

Usage Example:

用法示例

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

Note: #list_selectormust find an element that contains lielements

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

Plugin + Sort + Live Demo

插件 + 排序 + 现场演示

// 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>

回答by nullqube

// 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();

回答by Luca Detomi

Taking main inspiration from this W3 example, I developed a possible alternative and compact solution.

这个 W3 示例中获得主要灵感,我开发了一个可能的替代和紧凑的解决方案

In the example linked is possible to see 3 different options:

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

  • Filter only UL items
  • Filter any item
  • Filter any item with css animated effect
  • 仅过滤 UL 项目
  • 过滤任何项目
  • 使用 css 动画效果过滤任何项目

The simplest JS code is the following, that simply filter any kind of element thanks to $("#anyItemList *")selector:

最简单的 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);
    });
  });

In case that desired filtering would be only for ULlist, that selector could changed with $("#ulList li")(as in example)

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

If you want also to add css animation effect, there are some constraints:

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

  • Needed a pre-defined max-heightin px(maybe not so much impacting if you set an enough taller one)
  • overflow-y:hidden;
  • 需要一个预定义max-heightpx(如果你设置的足够高,可能不会有太大影响)
  • overflow-y:hidden;

So I was forced to declare:

所以我被迫声明:

#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;
}

Hiding effect is made with a combination of opacityand max-heightcss transitions, and border:0is necessary to override buttontag default browser style.

隐藏效果是通过opacitymax-heightcss 过渡的组合实现的,并且border:0是覆盖button标签默认浏览器样式所必需的。

In addition, in case of OLand ULlists is necessary to set list-style-position:inside;due to a strange default behaviour shared by Firefox and Chrome that hide bullets in case of default list-style-position:outside.

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

For Firefox this is a known bugsince 2003!!! but also Chrome has the same behaviour.

对于 Firefox,这是自 2003 年以来的一个已知错误!!!但 Chrome也有同样的行为