Как я могу настроить формат результатов подключаемого модуля автозаполнения?
-
19-09-2019 - |
Вопрос
я использую Плагин автозаполнения jQuery UI.Есть ли способ выделить последовательность символов поиска в раскрывающихся результатах?
Например, если у меня есть данные «foo bar» и я набираю «foo», я получу «фу bar» в раскрывающемся списке, вот так:
Решение
Да, вы можете, если вы используете автозаполнение обезьяны.
В виджете автозаполнения, включенном в версию 1.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(...)
.
Это хак, потому что:
для каждого элемента, отображаемого в списке, создается объект регулярного выражения.Этот объект регулярного выражения следует повторно использовать для всех элементов.
для форматирования завершенной части не используется класс 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();
jQueryUI 1.9.0 меняет принцип работы _renderItem.
Код ниже учитывает это изменение, а также показывает, как я выполнял сопоставление выделенных участков с помощью плагина jQuery Autocomplete Йорна Цефферера.Он выделит все отдельные термины в общем поисковом запросе.
После перехода на использование 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();
});
Вот полный функциональный пример:
<!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>
Надеюсь это поможет
для еще более простого способа попробуйте следующее:
$('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 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);
};
Вот версия, которая не требует каких-либо регулярных выражений и соответствует нескольким результатам в метке.
$.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);
};
Взгляните на демонстрацию комбобокса, она включает в себя подсветку результатов: http://jqueryui.com/demos/autocomplete/#combobox
Используемое там регулярное выражение также имеет дело с результатами HTML.
Вот моя версия:
- Использует функции DOM вместо RegEx для разрыва строк/вставки тегов диапазона.
- Затрагивается только указанное автозаполнение, а не все
- Работает с версией пользовательского интерфейса 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);
};
вы можете использовать следующий код:
библиотека:
$.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#url_or_dataoptions
(см. вкладку «Параметры»)
Для поддержки нескольких значений просто добавьте следующую функцию:
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>");