使用 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
Filtering a list as you type with jQuery
提问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 ul
has an id
of theList
, the following would be one way of doing it.
假设您ul
有一个id
of 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 score
method in PHPmethod, which has been ported to JavaScript by LiquidMetal.score
and joshaven's string.score
注意:它依赖于 PHP方法中的Quicksilverscore
方法,该方法已由joshavenLiquidMetal.score
和joshaven移植到 JavaScriptstring.score
Usage Example:
用法示例:
$("#text_box_selector").liveUpdate("#list_selector");
Note: #list_selector
must find an element that contains li
elements
注意:#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 UL
list, 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-height
inpx
(maybe not so much impacting if you set an enough taller one) overflow-y:hidden;
- 需要一个预定义
max-height
的px
(如果你设置的足够高,可能不会有太大影响) 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 opacity
and max-height
css transitions, and border:0
is necessary to override button
tag default browser style.
隐藏效果是通过opacity
和max-height
css 过渡的组合实现的,并且border:0
是覆盖button
标签默认浏览器样式所必需的。
In addition, in case of OL
and UL
lists 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 的情况下隐藏项目符号,因此有必要设置OL
和UL
列表。list-style-position:inside;
list-style-position:outside
For Firefox this is a known bugsince 2003!!! but also Chrome has the same behaviour.