Javascript 如何自定义格式自动完成插件结果?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2435964/
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
How can I custom-format the Autocomplete plug-in results?
提问by dev.e.loper
I'm using the jQuery UI Autocomplete plug-in. Is there a way to highlight search character sequence in drop-down results?
我正在使用jQuery UI 自动完成插件。有没有办法在下拉结果中突出显示搜索字符序列?
For example, if I have “foo bar” as data and I type "foo" I'll get “foobar” in the drop-down, like this:
例如,如果我将“foo bar”作为数据并输入“foo”,我将在下拉列表中得到“ foobar”,如下所示:
回答by Cheeso
Yes, you can if you monkey-patch autocomplete.
是的,如果您使用猴子补丁自动完成,您可以。
In the autocomplete widget included in v1.8rc3 of jQuery UI, the popup of suggestions is created in the _renderMenu function of the autocomplete widget. This function is defined like this:
在 jQuery UI 的 v1.8rc3 中包含的自动完成小部件中,建议的弹出窗口是在自动完成小部件的 _renderMenu 函数中创建的。这个函数是这样定义的:
_renderMenu: function( ul, items ) {
var self = this;
$.each( items, function( index, item ) {
self._renderItem( ul, item );
});
},
The _renderItem function is defined like this:
_renderItem 函数定义如下:
_renderItem: function( ul, item) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + item.label + "</a>" )
.appendTo( ul );
},
So what you need to do is replace that _renderItem fn with your own creation that produces the desired effect. This technique, redefining an internal function in a library, I have come to learn is called monkey-patching. Here's how I did it:
因此,您需要做的是将 _renderItem fn 替换为您自己的创作,从而产生所需的效果。这种在库中重新定义内部函数的技术,我是来学习的,叫做monkey-patching。这是我如何做到的:
function monkeyPatchAutocomplete() {
// don't really need this, but in case I did, I could store it and chain
var oldFn = $.ui.autocomplete.prototype._renderItem;
$.ui.autocomplete.prototype._renderItem = function( ul, item) {
var re = new RegExp("^" + this.term) ;
var t = item.label.replace(re,"<span style='font-weight:bold;color:Blue;'>" +
this.term +
"</span>");
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + t + "</a>" )
.appendTo( ul );
};
}
Call that function once in $(document).ready(...).
在$(document).ready(...).
Now, this is a hack, because:
现在,这是一个黑客,因为:
there's a regexp obj created for every item rendered in the list. That regexp obj ought to be re-used for all items.
there's no css class used for the formatting of the completed part. It's an inline style.
This means if you had multiple autocompletes on the same page, they'd all get the same treatment. A css style would solve that.
为列表中呈现的每个项目创建了一个正则表达式 obj。该正则表达式 obj 应该重新用于所有项目。
没有用于格式化已完成部分的 css 类。这是一种内联样式。
这意味着如果您在同一页面上有多个自动完成,它们都会得到相同的处理。css 样式可以解决这个问题。
...but it illustrates the main technique, and it works for your basic requirements.
...但它说明了主要技术,它适用于您的基本要求。


updated working example: http://output.jsbin.com/qixaxinuhe
更新的工作示例:http: //output.jsbin.com/qixaxinuhe
To preserve the case of the match strings, as opposed to using the case of the typed characters, use this line:
要保留匹配字符串的大小写,而不是使用键入字符的大小写,请使用以下行:
var t = item.label.replace(re,"<span style='font-weight:bold;color:Blue;'>" +
"$&" +
"</span>");
In other words, starting from the original code above, you just need to replace this.termwith "$&".
换句话说,从上面的原始代码开始,您只需要替换this.term为"$&".
EDIT
The above changes everyautocomplete widget on the page. If you want to change only one, see this question:
How to patch *just one* instance of Autocomplete on a page?
编辑
以上更改了页面上的每个自动完成小部件。如果您只想更改一个,请参阅此问题:
如何在页面上修补 * 仅一个 * 自动完成实例?
回答by Raj
this also works:
这也有效:
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
item.label = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong></strong>");
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + "</a>")
.appendTo(ul);
};
a combination of @J?rn Zaefferer and @Cheeso's responses.
@J?rn Zaefferer 和 @Cheeso 的回答的组合。
回答by orolo
Super helpful. Thank you. +1.
超级有帮助。谢谢你。+1。
Here is a light version that sorts on "String must begin with the term":
这是一个轻量级的版本,它对“字符串必须以术语开头”进行排序:
function hackAutocomplete(){
$.extend($.ui.autocomplete, {
filter: function(array, term){
var matcher = new RegExp("^" + term, "i");
return $.grep(array, function(value){
return matcher.test(value.label || value.value || value);
});
}
});
}
hackAutocomplete();
回答by 79IT
jQueryUI 1.9.0 changes how _renderItem works.
jQueryUI 1.9.0 改变了 _renderItem 的工作方式。
The code below takes this change into consideration and also shows how I was doing highlight matching using J?rn Zaefferer's jQuery Autocomplete plugin. It will highlight all individual terms in the overall search term.
下面的代码考虑了这一变化,并展示了我如何使用 J?rn Zaefferer 的 jQuery Autocomplete 插件进行高亮匹配。它将突出显示整个搜索词中的所有单个词。
Since moving to using Knockout and jqAuto I found this a much easier way of styling the results.
自从开始使用 Knockout 和 jqAuto 后,我发现这是一种更简单的样式化结果方式。
function monkeyPatchAutocomplete() {
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
// Escape any regex syntax inside this.term
var cleanTerm = this.term.replace(/[-\/\^$*+?.()|[\]{}]/g, '\$&');
// Build pipe separated string of terms to highlight
var keywords = $.trim(cleanTerm).replace(' ', ' ').split(' ').join('|');
// Get the new label text to use with matched terms wrapped
// in a span tag with a class to do the highlighting
var re = new RegExp("(" + keywords + ")", "gi");
var output = item.label.replace(re,
'<span class="ui-menu-item-highlight"></span>');
return $("<li>")
.append($("<a>").html(output))
.appendTo(ul);
};
};
$(function () {
monkeyPatchAutocomplete();
});
回答by Fabio Nolasco
Here it goes, a functional full example:
这是一个功能完整的示例:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Autocomplete - jQuery</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css">
</head>
<body>
<form id="form1" name="form1" method="post" action="">
<label for="search"></label>
<input type="text" name="search" id="search" />
</form>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<script>
$(function(){
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
item.label = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong></strong>");
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + "</a>")
.appendTo(ul);
};
var availableTags = [
"JavaScript",
"ActionScript",
"C++",
"Delphi",
"Cobol",
"Java",
"Ruby",
"Python",
"Perl",
"Groove",
"Lisp",
"Pascal",
"Assembly",
"Cliper",
];
$('#search').autocomplete({
source: availableTags,
minLength: 3
});
});
</script>
</body>
</html>
Hope this helps
希望这可以帮助
回答by Pierre
Here's a rehash of Ted de Koning's solution. It includes :
这是 Ted de Koning 解决方案的重述。这包括 :
- Case insensitive search
- Finding many occurrences of the searched string
- 不区分大小写的搜索
- 查找多次出现的搜索字符串
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
var sNeedle = item.label;
var iTermLength = this.term.length;
var tStrPos = new Array(); //Positions of this.term in string
var iPointer = 0;
var sOutput = '';
//Change style here
var sPrefix = '<strong style="color:#3399FF">';
var sSuffix = '</strong>';
//Find all occurences positions
tTemp = item.label.toLowerCase().split(this.term.toLowerCase());
var CharCount = 0;
tTemp[-1] = '';
for(i=0;i<tTemp.length;i++){
CharCount += tTemp[i-1].length;
tStrPos[i] = CharCount + (i * iTermLength) + tTemp[i].length
}
//Apply style
i=0;
if(tStrPos.length > 0){
while(iPointer < sNeedle.length){
if(i<=tStrPos.length){
//Needle
if(iPointer == tStrPos[i]){
sOutput += sPrefix + sNeedle.substring(iPointer, iPointer + iTermLength) + sSuffix;
iPointer += iTermLength;
i++;
}
else{
sOutput += sNeedle.substring(iPointer, tStrPos[i]);
iPointer = tStrPos[i];
}
}
}
}
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + sOutput + "</a>")
.appendTo(ul);
};
回答by Aaron
for an even easier way, try this:
更简单的方法,试试这个:
$('ul: li: a[class=ui-corner-all]').each (function (){
//grab each text value
var text1 = $(this).text();
//grab user input from the search box
var val = $('#s').val()
//convert
re = new RegExp(val, "ig")
//match with the converted value
matchNew = text1.match(re);
//Find the reg expression, replace it with blue coloring/
text = text1.replace(matchNew, ("<span style='font-weight:bold;color:green;'>") + matchNew + ("</span>"));
$(this).html(text)
});
}
回答by Ted de Koning
Here is a version that does not require any regular expressions and matches multiple results in the label.
这是一个不需要任何正则表达式并匹配标签中的多个结果的版本。
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
var highlighted = item.label.split(this.term).join('<strong>' + this.term + '</strong>');
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + highlighted + "</a>")
.appendTo(ul);
};
回答by J?rn Zaefferer
Take a look at the combobox demo, it includes result highlighting: http://jqueryui.com/demos/autocomplete/#combobox
看一下组合框演示,它包括结果突出显示:http: //jqueryui.com/demos/autocomplete/#combobox
The regex in use there also deals with html results.
那里使用的正则表达式也处理 html 结果。
回答by Salman A
Here is my version:
这是我的版本:
- Uses DOM functions instead of RegEx to break strings/inject span tags
- Only the specified autocomplete is affected, not all
- Works with UI version 1.9.x
- 使用 DOM 函数而不是 RegEx 来打破字符串/注入 span 标签
- 仅影响指定的自动完成,而不是全部
- 适用于 UI 版本 1.9.x
function highlightText(text, $node) {
var searchText = $.trim(text).toLowerCase(),
currentNode = $node.get(0).firstChild,
matchIndex,
newTextNode,
newSpanNode;
while ((matchIndex = currentNode.data.toLowerCase().indexOf(searchText)) >= 0) {
newTextNode = currentNode.splitText(matchIndex);
currentNode = newTextNode.splitText(searchText.length);
newSpanNode = document.createElement("span");
newSpanNode.className = "highlight";
currentNode.parentNode.insertBefore(newSpanNode, currentNode);
newSpanNode.appendChild(newTextNode);
}
}
$("#autocomplete").autocomplete({
source: data
}).data("ui-autocomplete")._renderItem = function (ul, item) {
var $a = $("<a></a>").text(item.label);
highlightText(this.term, $a);
return $("<li></li>").append($a).appendTo(ul);
};

