Як я можу відформатувати результати плагіна автоматичного заповнення?


167

Я використовую плагін автоматичного завершення інтерфейсу jQuery UI . Чи є спосіб виділити послідовність пошукових символів у випадаючих результатах?

Наприклад, якщо у мене є дані "foo bar" в якості даних і я введіть "foo", я отримаю " foo bar" у спадному меню, як це:

"Сніданок" з'являється після того, як "Bre" набирається "Bre", що має жирний тип, і "akfast", що має легкий.

Відповіді:


233

Автозаповнюється живою пропозицією

Так, ви можете, якщо ви заповнили автозаповнення.

У віджеті автозаповнення, включеному в 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(...).

Тепер це хак, тому що:

  • для кожного елемента, відображеного у списку, створено obge regexp. Цей regexp obj повинен бути використаний для всіх елементів.

  • не існує класу css, який використовується для форматування завершеної частини. Це стиль inline.
    Це означає, що якщо у вас було кілька автозаповнення на одній сторінці, всі вони отримали б одне і те ж лікування. Стиль css вирішив би це.

... але вона ілюструє основну техніку, і вона працює для ваших основних вимог.

alt текст

оновлений приклад роботи: http://output.jsbin.com/qixaxinuhe


Щоб зберегти випадок рядків збігу, на відміну від використання регістру введених символів, використовуйте цей рядок:

var t = item.label.replace(re,"<span style='font-weight:bold;color:Blue;'>" + 
          "$&" + 
          "</span>");

Іншими словами, починаючи з вихідного коду вище, вам просто потрібно замінити this.termз "$&".


РЕДАКТУВАННЯ
Наведене вище змінює кожен віджет автозаповнення на сторінці. Якщо ви хочете змінити лише одне, див. Це питання:
Як виправити * лише один * екземпляр автозаповнення на сторінці?


Спасибі Чісо. Чи є у вас посилання jsbin для цього?
dev.e.loper

1
Зверніть увагу, що якщо ви робите ланцюжок разом, важливо скинути контекст: oldFn.apply (це, [ul, item]);
еманатон

Велике спасибі! Було б дивним, якби це стало частиною інтерфейсу jQuery.
Девід Райдер

4
Я б сказав, що якщо ви хочете, щоб він зміцнював результат у будь-якій частині збігованого рядка (не тільки на початку), змініть рядок RegExp на це: var re = new RegExp (this.term);
Девід Райдер

1
Автоматичне завершення JQueryUI, за замовчуванням, робить нечутливий до регістру пошук, тому має сенс додати прапор "i" в об'єкт RegExp. Немає жодних причин використовувати "^" в регексі, як згадував @DavidRyder. Як: var re = new RegExp(this.term, "i"); Чудовий пост!
Сем

65

це також працює:

       $.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);
        };

комбінація відповідей @ Йорна Зеферера та @ Cheeso.


Це мені сподобалось краще, оскільки воно відповідає цілому слову.
atp

3
Це добре працює. Єдине, на що слід звернути увагу, це те, що item.label замінюється. Для мене я отримував "<strong ..." у своєму текстовому полі. Просто присвоєння результату заміни іншій змінній очистив цю програму. У вас би не виникло цієї проблеми, якщо ваші дані містять властивість значення, яка потрапляє у текстове поле.
Kijana Woodard

це не працює, якщо у вас є автозаповнення, яке підтримує кілька значень. будь-які пропозиції?
leora

Найпростіший спосіб отримати підсвічування тексту в результатах автозаповнення. Очевидно, слідкуйте за помилками, на які вказували леора та Кіана вище
adamst85

@RNKushwaha де завгодно, перш ніж дзвонити$().autocomplete()
Брайан Лейшман

8

Супер корисно. Дякую. +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();

1
Спасибі Ороло, я використовував автозаповнення в декількох місцях і хотів центрального місця, де я можу внести зміни, щоб показати лише результат, який починається з набраних символів, і це саме те, що мені точно потрібно!
dreamerkumar

Дякую. Це найкраще рішення з усіх. Він працює для нечутливих до випадків.
Анікет Кулкарні

7

Ось це, функціональний повний приклад:

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

Сподіваюся, це допомагає


6

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

Коли я шукаю такі символи, як '(' це спричиняє помилку ("Uncaught SyntaxError: Неправильний регулярний вираз: / (sam | at | () /: Unterminated group") щоб вирішити це шляхом запобігання зіткнення з регулярними виразами?
Idan Shechter

Дивовижна відповідь! Любіть, що він виділяє умови незалежно від місця їх появи. Дуже круто. Дякуємо за оновлення публікації. Одне із запитань у мене стосується класу .ui-menu-item-виділення, який ви використовуєте. Чи очікується, що це визначатиметься jquery-ui або споживачами? Я змінив назву класу, щоб відповідати власним засобам і просто зробив вагу шрифту жирним. .jqAutocompleteMatch { font-weight: bold; }
Сем

@IdanShechter Чудовий коментар. this.termПеред тим, як проводити будь-яку обробку, слід використовувати певну логіку для виходу з регулярного виразу. Дивіться рядок Escape для використання в регулярному вираженні Javascript як одну з багатьох відповідей, як це зробити.
Сем

3

для ще простішого способу спробуйте це:

$('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)
});
  }

3

Ось перегляд рішення Теда де Конінга. Це включає :

  • Пошук нечутливий
  • Знаходження багатьох випадків пошуку рядка
$.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);
};

1
Думаю, ви заново вигадуєте колесо! Чому ви не використовуєте регулярні вирази, які швидші, простіші та компактніші, ніж весь цей код?
Джордж Маврицакіс

2

Ось версія, яка не вимагає регулярних виразів і відповідає декільком результатам на етикетці.

$.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);
};

Це, мабуть, найкраще рішення, але string.split здатний проводити лише відповідність регістру матчів.
Ноель Абрахамс

Чи є у вас який-небудь спосіб зіставити слова на основі чутливих до регістру? Тому що якщо у мене є пошуковий "альфа", він не виділить "Альфу"
Патрік

1

Погляньте на демонстраційну комбінацію, вона включає підсвічування результатів: http://jqueryui.com/demos/autocomplete/#combobox

Регекс, який використовується тут, також стосується результатів html.


більше не з’являється (наскільки я можу сказати)
Сем,

1

Ось моя версія:

  • Використовує функції 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);
};

Виділіть приклад відповідного тексту


1

Ви можете використовувати наступний код:

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оригінальний прототип плагіна.

у моєму прикладі також використовується оригінальна функція візуалізації для спрощення коду

важливо, якщо ви хочете використовувати плагін у різних місцях з різним видом автозаповнення і не хочете порушувати свій код.


Як правило, краще витратити час на відповіді на новіші запитання або на відповіді без відповідей, аніж на відповіді на 6-річне запитання, на яке вже відповіли.
zchrykng

0

Якщо ви замість цього використовуєте плагін сторонньої сторони, він має варіант виділення: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(див. вкладку Параметри)


так, я знаю про цей плагін. Однак ми використовуємо jQueryUI у своєму додатку, тому було б непогано налагодити цю роботу з jQueryUI Autocomplete плагіном
dev.e.loper

1
Станом на 2010-06-23, плагін jQuery Autocomplete був застарілий на користь плагіна автоматичного заповнення інтерфейсу jQuery. Див bassistance.de/jquery-plugins/jquery-plugin-autocomplete для отримання додаткової інформації
ши

0

Для підтримки декількох значень просто додайте наступну функцію:

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>");
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.