Как я могу отформатировать результаты плагина автозаполнения?
Я использую плагин автозаполнения пользовательского интерфейса jQuery. Есть ли способ выделить последовательность символов поиска в раскрывающихся результатах?
Например, если у меня есть "foo bar" в качестве данных и я ввожу "foo", я получу "foo bar" в раскрывающемся меню, например:
13 ответов
Да, вы можете, если у вас есть автозаполнение.
В виджете автозаполнения, включенном в v1.8rc3 пользовательского интерфейса jQuery, всплывающее окно с подсказками создается в функции _renderMenu виджета автозаполнения. Эта функция определяется следующим образом:
_renderMenu: function( ul, items ) {
var self = this;
$.each( items, function( index, item ) {
self._renderItem( ul, item );
});
},
Функция _renderItem определяется следующим образом:
_renderItem: function( ul, item) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + item.label + "</a>" )
.appendTo( ul );
},
Так что вам нужно заменить это _renderItem fn своим собственным созданием, которое производит желаемый эффект. Этот метод, переопределяющий внутреннюю функцию в библиотеке, я пришел к изучению, называется патч-аппликация. Вот как я это сделал:
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 );
};
}
Вызовите эту функцию один раз в $(document).ready(...)
,
Это хак, потому что:
Для каждого элемента, представленного в списке, создается регулярное выражение obj. Это регулярное выражение obj должно быть повторно использовано для всех элементов.
нет класса css, используемого для форматирования законченной части. Это встроенный стиль.
Это означает, что если бы у вас было несколько автозаполнений на одной странице, они все получили бы одинаковую обработку. Стиль CSS поможет решить эту проблему.
... но он иллюстрирует основную технику и работает для ваших основных требований.
обновленный рабочий пример: http://output.jsbin.com/qixaxinuhe
Чтобы сохранить регистр строк совпадения, в отличие от использования регистра напечатанных символов, используйте эту строку:
var t = item.label.replace(re,"<span style='font-weight:bold;color:Blue;'>" +
"$&" +
"</span>");
Другими словами, начиная с исходного кода выше, вам просто нужно заменить this.term
с "$&"
,
РЕДАКТИРОВАТЬ
Вышеизложенное изменяет каждый виджет автозаполнения на странице. Если вы хотите изменить только один, посмотрите этот вопрос:
Как установить * только один * экземпляр автозаполнения на странице?
Это также работает:
$.ui.autocomplete.prototype._renderItem = function (ul, item) {
item.label = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + "</a>")
.appendTo(ul);
};
комбинация ответов @Jörn Zaefferer и @Cheeso.
Супер полезно. Спасибо. +1.
Вот облегченная версия, которая сортирует слова "строка должна начинаться с термина":
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();
Вот он, функциональный полный пример:
<!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>$1</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>
Надеюсь это поможет
jQueryUI 1.9.0 меняет работу _renderItem.
Приведенный ниже код учитывает это изменение, а также показывает, как я выполнял сопоставление выделенных фрагментов с помощью плагина JQuery Autocomplete от Jörn Zaefferer. Он выделит все отдельные термины в общем поисковом запросе.
С тех пор, как я перешел на использование 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">$1</span>');
return $("<li>")
.append($("<a>").html(output))
.appendTo(ul);
};
};
$(function () {
monkeyPatchAutocomplete();
});
Вот перефразировка решения Теда де Конинга. Это включает:
- Поиск без учета регистра
- Нахождение многих вхождений искомой строки
$.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);
};
Для еще более простого способа попробуйте это:
$('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)
});
}
Вот версия, которая не требует регулярных выражений и соответствует нескольким результатам в метке.
$.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);
};
Вот моя версия:
- Использует функции DOM вместо RegEx для разбиения строк / вставки тегов span
- Затрагивается только указанное автозаполнение, не все
- Работает с пользовательским интерфейсом версии 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);
};
Взгляните на демонстрацию combobox, она включает в себя выделение результатов: http://jqueryui.com/demos/autocomplete/
Используемое здесь регулярное выражение также имеет дело с результатами html.
Вы можете использовать следующий код:
Lib:
$.widget("custom.highlightedautocomplete", $.ui.autocomplete, {
_renderItem: function (ul, item) {
var $li = $.ui.autocomplete.prototype._renderItem.call(this,ul,item);
//any manipulation with li
return $li;
}
});
и логика:
$('selector').highlightedautocomplete({...});
он создает собственный виджет, который может переопределить _renderItem
без перезаписи _renderItem
оригинального прототипа плагина.
в моем примере также используется оригинальная функция рендеринга для упрощения кода
это важно, если вы хотите использовать плагин в разных местах с разным представлением автозаполнения и не хотите ломать свой код.
Если вместо этого вы используете сторонний плагин, у него есть опция выделения: http://docs.jquery.com/Plugins/Autocomplete/autocomplete
(см. вкладку "Параметры")
Для поддержки нескольких значений просто добавьте следующую функцию:
function getLastTerm( term ) {
return split( term ).pop();
}
var t = String(item.value).replace(new RegExp(getLastTerm(this.term), "gi"), "<span class='ui-state-highlight'>$&</span>");