Làm cách nào tôi có thể định dạng tùy chỉnh kết quả trình cắm tự động hoàn thành?


167

Tôi đang sử dụng trình cắm tự động giao diện người dùng jQuery . Có cách nào để làm nổi bật chuỗi ký tự tìm kiếm trong kết quả thả xuống không?

Ví dụ: nếu tôi có dữ liệu thanh foo thanh dữ liệu và tôi gõ "foo" thì tôi sẽ nhận được thanh foo bar thanh trong phần thả xuống, như thế này:

Bữa sáng ăn trưa xuất hiện sau khi ăn được Bre Bre được gõ với kiểu chữ Bre Bre có kiểu chữ đậm và chữ ak akastast có một cái nhẹ.

Câu trả lời:


233

Tự động hoàn thành với đề xuất trực tiếp

Có, bạn có thể nếu bạn tự động hoàn thành bản vá khỉ.

Trong tiện ích tự động hoàn thành có trong v1.8rc3 của Giao diện người dùng jQuery, cửa sổ bật lên của các đề xuất được tạo trong hàm _renderMothy của tiện ích tự động hoàn tất. Hàm này được định nghĩa như thế này:

_renderMenu: function( ul, items ) {
    var self = this;
    $.each( items, function( index, item ) {
        self._renderItem( ul, item );
    });
},

Hàm _renderItem được định nghĩa như thế này:

_renderItem: function( ul, item) {
    return $( "<li></li>" )
        .data( "item.autocomplete", item )
        .append( "<a>" + item.label + "</a>" )
        .appendTo( ul );
},

Vì vậy, những gì bạn cần làm là thay thế _renderItem fn bằng sáng tạo của riêng bạn tạo ra hiệu ứng mong muốn. Kỹ thuật này, xác định lại một chức năng nội bộ trong một thư viện, tôi đã tìm hiểu được gọi là vá khỉ . Đây là cách tôi đã làm:

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

Gọi chức năng đó một lần trong $(document).ready(...).

Bây giờ, đây là một hack, bởi vì:

  • có một obj regrec được tạo cho mọi mục được hiển thị trong danh sách. Điều đó regrec obj nên được sử dụng lại cho tất cả các mục.

  • không có lớp css nào được sử dụng để định dạng phần hoàn thành. Đó là một phong cách nội tuyến.
    Điều này có nghĩa là nếu bạn có nhiều tự động hoàn thành trên cùng một trang, tất cả chúng đều được xử lý như nhau. Một phong cách css sẽ giải quyết điều đó.

... nhưng nó minh họa kỹ thuật chính, và nó hoạt động cho các yêu cầu cơ bản của bạn.

văn bản thay thế

ví dụ làm việc được cập nhật: http://output.jsbin.com/qixaxinuhe


Để bảo vệ trường hợp của chuỗi khớp, trái với trường hợp sử dụng các ký tự được nhập, hãy sử dụng dòng này:

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

Nói cách khác, bắt đầu từ mã gốc ở trên, bạn chỉ cần thay thế this.termbằng "$&".


EDIT
Trên đây thay đổi mọi tiện ích tự động hoàn thành trên trang. Nếu bạn chỉ muốn thay đổi một, hãy xem câu hỏi này:
Cách vá * chỉ một * bản sao của Tự động hoàn tất trên một trang?


Cảm ơn Cheeso. Bạn có liên kết jsbin cho điều này?
dev.e.loper

1
Lưu ý rằng nếu bạn thực hiện chuỗi mọi thứ cùng, điều quan trọng là phải đặt lại bối cảnh: oldFn.apply (this, [ul, item]);
emanaton

Cảm ơn rât nhiều! Sẽ thật tuyệt vời nếu điều này trở thành một phần của Giao diện người dùng jQuery.
David Ryder

4
Một điều tôi muốn nói là nếu bạn muốn nó in đậm kết quả trong bất kỳ phần nào của chuỗi khớp (không chỉ phần đầu) sửa đổi dòng RegExp thành này: var re = new RegExp (this.term);
David Ryder

1
JQueryUI tự động hoàn tất xuất hiện để thực hiện tìm kiếm không phân biệt chữ hoa chữ thường, do đó, việc thêm cờ "i" trong đối tượng RegExp là điều hợp lý. Cũng không có lý do để sử dụng "^" trong regex như @DavidRyder đã đề cập. Giống như: var re = new RegExp(this.term, "i"); Bài đăng tuyệt vời!
Sam

65

cái này cũng hoạt động:

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

sự kết hợp của phản hồi @ Jorn Zaefferer và @ Cheeso.


Tôi thích cái này hơn, vì nó phù hợp với toàn bộ từ.
atp

3
Điều này hoạt động tốt. Điều duy nhất cần chú ý là item.label đang được thay thế. Đối với tôi, tôi đã nhận được "<strong ..." trong hộp văn bản của mình. Chỉ cần gán kết quả thay thế cho một biến khác đã xóa nó lên. Bạn sẽ không gặp vấn đề này nếu dữ liệu của bạn chứa thuộc tính giá trị được đưa vào hộp văn bản.
Kijana Woodard

điều này không hoạt động nếu bạn có tự động hoàn thành hỗ trợ nhiều giá trị. bất kỳ đề xuất?
leora

Cách đơn giản nhất để làm nổi bật văn bản trong kết quả tự động hoàn thành của bạn. Rõ ràng là tìm ra các lỗi như được chỉ ra bởi leora và Kijana ở trên
adamst85

@RNKushwaha bất cứ nơi nào trước khi bạn gọi tới$().autocomplete()
Brian Leishman

8

Siêu hữu ích. Cảm ơn bạn. +1.

Đây là phiên bản nhẹ sắp xếp theo "Chuỗi phải bắt đầu bằng thuật ngữ":

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
Cảm ơn Orolo, tôi đã sử dụng tự động hoàn thành tại nhiều địa điểm và muốn một vị trí trung tâm nơi tôi có thể thực hiện thay đổi để chỉ hiển thị kết quả bắt đầu bằng các ký tự được nhập và đây là thứ tôi thực sự cần!
dreamerkumar

Cảm ơn. Đây là giải pháp tốt nhất của tất cả. Nó hoạt động cho trường hợp không nhạy cảm.
Aniket Kulkarni

7

Ở đây, một ví dụ đầy đủ chức năng:

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

Hi vọng điêu nay co ich


6

jQueryUI 1.9.0 thay đổi cách hoạt động của _renderItem.

Đoạn mã dưới đây sẽ xem xét sự thay đổi này và cũng cho thấy cách tôi thực hiện kết hợp đánh dấu bằng cách sử dụng plugin jQuery Autocomplete của Jörn Zaefferer. Nó sẽ làm nổi bật tất cả các thuật ngữ riêng lẻ trong thuật ngữ tìm kiếm tổng thể.

Kể từ khi chuyển sang sử dụng Knockout và jqAuto, tôi thấy đây là cách dễ dàng hơn nhiều để tạo kiểu cho kết quả.

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

Khi tôi tìm kiếm với các ký tự như '(' nó gây ra lỗi ("Uncaught SyntaxError: Biểu thức chính quy không hợp lệ: / (sam | at | () /: Nhóm bị hủy bỏ") để giải quyết vấn đề này bằng cách ngăn chặn sự va chạm với regex?
Idan Shechter

Câu trả lời tuyệt vời! Tình yêu mà nó làm nổi bật các điều khoản bất kể nơi chúng xuất hiện. Rất tuyệt. Cảm ơn đã cập nhật bài viết. Một câu hỏi tôi đã có là về lớp .ui-menu-item-highlight bạn sử dụng. Điều này dự kiến ​​sẽ được xác định bởi jquery-ui hoặc bởi người tiêu dùng? Tôi đã thay đổi tên lớp để phù hợp với phương tiện của riêng tôi và chỉ đơn giản là làm cho chữ in đậm. .jqAutocompleteMatch { font-weight: bold; }
Sam

@IdanShechter Nhận xét tuyệt vời. Một số logic để thoát this.termregex nên được sử dụng trước khi thực hiện bất kỳ xử lý nào. Xem chuỗi Escape để sử dụng trong regex Javascript là một trong nhiều câu trả lời cho cách thực hiện việc này.
Sam

3

cho một cách thậm chí dễ dàng hơn, hãy thử điều này:

$('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

Đây là một bản thử nghiệm lại giải pháp của Ted de Koning. Nó bao gồm :

  • Trường hợp tìm kiếm không nhạy cảm
  • Tìm nhiều lần xuất hiện của chuỗi tìm kiếm
$.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
Tôi nghĩ rằng bạn đang phát minh lại bánh xe! Tại sao bạn không sử dụng các biểu thức thông thường nhanh hơn, dễ dàng hơn và gọn hơn tất cả các mã này?
George Mavritsakis

2

Đây là phiên bản không yêu cầu bất kỳ biểu thức chính quy nào và khớp với nhiều kết quả trong nhãn.

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

Đây có lẽ là giải pháp tốt nhất, nhưng tôi tin rằng string.split chỉ có thể phù hợp với các trường hợp phân biệt chữ hoa chữ thường.
Noel Abrahams

Bạn có cách nào để ghép các từ dựa trên không phân biệt chữ hoa chữ thường không? Bởi vì nếu tôi có một tìm kiếm "alfa", nó sẽ không làm nổi bật "Alfa"
Patrick


1

Đây là phiên bản của tôi:

  • Sử dụng các hàm DOM thay vì RegEx để ngắt chuỗi / tiêm thẻ span
  • Chỉ tự động hoàn thành được chỉ định bị ảnh hưởng, không phải tất cả
  • Hoạt động với giao diện người dùng 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);
};

Làm nổi bật ví dụ văn bản phù hợp


1

bạn có thể sử dụng mã folowing:

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

và logic:

$('selector').highlightedautocomplete({...});

nó tạo ra widget tùy chỉnh có thể ghi đè _renderItemmà không ghi đè lên _renderItemnguyên mẫu plugin gốc.

trong ví dụ của tôi cũng đã sử dụng chức năng kết xuất ban đầu để đơn giản hóa một số mã

đó là điều quan trọng nếu bạn muốn sử dụng plugin ở những nơi khác nhau với chế độ xem tự động hoàn thành khác nhau và không muốn phá vỡ mã của bạn.


Nói chung, tốt hơn là dành thời gian để trả lời các câu hỏi mới hơn, hoặc câu hỏi không có câu trả lời hơn là trả lời một câu hỏi 6 tuổi đã được trả lời.
zchrykng

0

Thay vào đó, nếu bạn sử dụng plugin của bên thứ 3, nó có tùy chọn nổi bật: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(xem tab Tùy chọn)


vâng tôi biết về trình cắm này. Tuy nhiên, chúng tôi đang sử dụng jQueryUI trong ứng dụng của mình, vì vậy thật tuyệt khi làm việc với trình cắm tự động hoàn chỉnh jQueryUI
dev.e.loper

1
Kể từ 2010-06-23, plugin Tự động hoàn thành jQuery đã không được hỗ trợ cho plugin Tự động hoàn thành giao diện người dùng jQuery. Xem bassistance.de/jquery-plugins/jquery-plugin-autocomplete để biết thêm thông tin
shek

0

Để hỗ trợ nhiều giá trị, chỉ cần thêm chức năng sau:

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>");
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.