ฉันจะกำหนดรูปแบบผลลัพธ์ปลั๊กอินการเติมข้อความอัตโนมัติได้อย่างไร


167

ฉันใช้jQuery UI การเติมข้อความอัตโนมัติ Plug-in มีวิธีการเน้นลำดับอักขระการค้นหาในผลลัพธ์แบบหล่นลงหรือไม่

ตัวอย่างเช่นถ้าฉันมี "foo bar" เป็นข้อมูลและฉันพิมพ์ "foo" ฉันจะได้รับ " foo bar" ในรายการแบบหล่นลงเช่นนี้

“ อาหารเช้า” จะปรากฏขึ้นหลังจากพิมพ์“ Bre” ด้วย“ Bre” ที่มีประเภทที่หนาและ“ akfast” จะมีสีอ่อน

คำตอบ:


233

เติมข้อความอัตโนมัติด้วยคำแนะนำสด

ใช่คุณสามารถทำได้ถ้าคุณลิงเติมข้อความอัตโนมัติ

ในวิดเจ็ตการเติมข้อความอัตโนมัติที่รวมอยู่ใน v1.8rc3 ของ jQuery UI จะมีการสร้างป๊อปอัปของข้อเสนอแนะในฟังก์ชัน _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 regexp สร้างขึ้นสำหรับทุกรายการที่แสดงในรายการ regexp obj นั้นควรนำมาใช้ใหม่สำหรับทุกรายการ

  • ไม่มีคลาส css ที่ใช้สำหรับการจัดรูปแบบของส่วนที่เสร็จสมบูรณ์ มันเป็นสไตล์อินไลน์
    ซึ่งหมายความว่าหากคุณมีการเติมข้อความอัตโนมัติหลายรายการในหน้าเดียวกันทุกคนจะได้รับการรักษาเหมือนกัน สไตล์ css จะแก้ปัญหานั้น

... แต่มันแสดงให้เห็นถึงเทคนิคหลักและใช้งานได้กับความต้องการขั้นพื้นฐานของคุณ

ข้อความแสดงแทน

อัปเดตตัวอย่างการทำงาน: http://output.jsbin.com/qixaxinuhe


ในการรักษาตัวพิมพ์เล็กของสตริงการจับคู่ซึ่งตรงข้ามกับการใช้ตัวพิมพ์ของอักขระให้ใช้บรรทัดนี้:

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

ในคำอื่น ๆ ที่เริ่มต้นจากรหัสเดิมข้างต้นคุณก็ต้องเปลี่ยนด้วยthis.term"$&"


แก้ไข
ข้างต้นเปลี่ยนทุกวิดเจ็ตเติมข้อความอัตโนมัติในหน้า หากคุณต้องการเปลี่ยนเพียงครั้งเดียวให้ดูคำถามนี้:
วิธีแก้ไข * เพียงหนึ่งอินสแตนซ์ของการเติมข้อความอัตโนมัติบนหน้าเว็บ


ขอบคุณ Cheeso คุณมีลิงค์ jsbin สำหรับสิ่งนี้หรือไม่?
dev.e.loper

1
โปรดทราบว่าหากคุณทำการเชื่อมโยงสิ่งต่าง ๆ สิ่งสำคัญคือการรีเซ็ตบริบท: oldFn.apply (สิ่งนี้, [ul, รายการ]);
emanaton

ขอบคุณมาก! คงจะดีมากถ้านี่เป็นส่วนหนึ่งของ jQuery UI
David Ryder

4
สิ่งหนึ่งที่ฉันจะพูดคือถ้าคุณต้องการให้ตัวหนาผลลัพธ์ในส่วนใด ๆ ของสตริงที่ตรงกัน (ไม่ใช่แค่จุดเริ่มต้น) แก้ไขบรรทัด RegExp เป็น: var re = new RegExp (this.term);
David Ryder

1
การเติมข้อความอัตโนมัติ JQueryUI ดูเหมือนจะทำการค้นหาแบบตัวเล็กและตัวเล็กตามค่าเริ่มต้นดังนั้นจึงเหมาะสมที่จะเพิ่มการตั้งค่าสถานะ "i" ในวัตถุ RegExp ไม่มีเหตุผลที่จะใช้ "^" ใน regex ตามที่ @DavidRyder พูดถึง ไลค์: var re = new RegExp(this.term, "i"); โพสต์ยอดเยี่ยม!
Sam

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

การรวมกันของการตอบกลับของ @ Jörn Zaefferer และ @ Cheeso


ฉันชอบอันนี้ดีกว่าเพราะมันตรงกับคำทั้งหมด
atp

3
มันใช้งานได้ดี สิ่งเดียวที่ต้องระวังคือ item.label กำลังถูกแทนที่ สำหรับฉันฉันได้รับ "<strong ... " ในกล่องข้อความของฉัน เพียงแค่กำหนดผลลัพธ์การแทนที่ให้กับตัวแปรอื่น ๆ คุณจะไม่มีปัญหานี้ถ้าข้อมูลของคุณมีคุณสมบัติค่าที่ใส่ลงในกล่องข้อความ
Kijana Woodard

สิ่งนี้จะไม่ทำงานหากคุณมีการเติมข้อความอัตโนมัติที่รองรับหลายค่า ข้อเสนอแนะใด ๆ
leora

วิธีที่ง่ายที่สุดในการเน้นข้อความในผลลัพธ์การเติมข้อความอัตโนมัติของคุณ เห็นได้ชัดว่ามองหาข้อบกพร่องตามที่ leora และ Kijana กล่าวไว้ข้างต้น
adamst85

@RNKushwaha ทุกที่ก่อนที่คุณจะโทรไป$().autocomplete()
Brian Leishman

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
ขอบคุณ Orolo ฉันใช้การเติมข้อความอัตโนมัติในหลาย ๆ ที่และต้องการสถานที่ส่วนกลางที่ฉันสามารถทำการเปลี่ยนแปลงเพื่อแสดงเฉพาะผลลัพธ์ที่เริ่มต้นด้วยตัวอักษรที่พิมพ์แล้วและนี่คือสิ่งที่ฉันต้องการจริงๆ!
dreamerkumar

ขอบคุณ นี่คือทางออกที่ดีที่สุดของทั้งหมด มันใช้งานไม่ได้กับตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
Aniket Kulkarni

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 | () /: กลุ่มที่ไม่ถูกทำลาย") ต่อไปเพื่อแก้ไขปัญหานี้โดยป้องกันการชนด้วย regex?
Idan Shechter

คำตอบที่ยอดเยี่ยม! รักว่ามันจะเน้นเงื่อนไขโดยไม่คำนึงถึงว่าพวกเขาปรากฏ เด็ดมาก ขอบคุณที่อัพเดทโพสต์ คำถามหนึ่งที่ฉันมีคือเกี่ยวกับคลาส. ui-menu-item-highlight ที่คุณใช้ สิ่งนี้คาดว่าจะถูกกำหนดโดย jquery-ui หรือโดยผู้บริโภค? ฉันเปลี่ยนชื่อชั้นเรียนเป็นชุดวิธีการของตัวเองและเพียงทำให้น้ำหนักตัวอักษรหนา .jqAutocompleteMatch { font-weight: bold; }
Sam

@IdanShechter ความคิดเห็นที่ดี ตรรกะบางอย่างที่ควรหลีกเลี่ยงthis.termสำหรับ for regex ก่อนที่จะทำการประมวลผลใด ๆ ดูEscape string สำหรับใช้ใน Javascript regexซึ่งเป็นหนึ่งในคำตอบมากมายสำหรับวิธีการทำสิ่งนี้
Sam

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

นี่คือรูปแบบใหม่ของโซลูชันของ Ted de Koning มันรวมถึง:

  • การค้นหาแบบคำนึงถึงขนาดตัวพิมพ์
  • การค้นหาสตริงการค้นหาที่เกิดขึ้นมากมาย
$.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
ฉันคิดว่าคุณกำลังคิดค้นวงล้อใหม่! ทำไมคุณไม่ใช้นิพจน์ทั่วไปที่เร็วกว่าง่ายกว่าและกะทัดรัดกว่าโค้ดนี้ทั้งหมด?
George Mavritsakis

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 สามารถจับคู่แบบตรงตามตัวพิมพ์ใหญ่ - เล็กได้
Noel Abrahams

คุณมีวิธีการจับคู่คำใด ๆ โดยยึดตามตัวพิมพ์เล็กหรือไม่ เพราะถ้าฉันมีการค้นหา "อัลฟ่า" มันจะไม่เน้น "อัลฟ่า"
แพทริค

1

ลองดูตัวอย่างของ combobox ซึ่งจะรวมถึงการเน้นผลลัพธ์: http://jqueryui.com/demos/autocomplete/#combobox

regex ที่ใช้งานอยู่ที่นั่นยังเกี่ยวข้องกับผลลัพธ์ html


ไม่ปรากฏอีกต่อไป (เท่าที่ผมสามารถบอกได้)
แซม

1

นี่คือรุ่นของฉัน:

  • ใช้ฟังก์ชั่น DOM แทน RegEx เพื่อแยกสตริง / ฉีดแท็กขยาย
  • การเติมข้อความอัตโนมัติที่ระบุเท่านั้นที่ได้รับผลกระทบไม่ใช่ทั้งหมด
  • ทำงานร่วมกับ 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);
};

เน้นตัวอย่างข้อความที่ตรงกัน


1

คุณสามารถใช้รหัส 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;
    }
});

และตรรกะ:

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

มันสร้างเครื่องมือที่กำหนดเองที่สามารถแทนที่ได้_renderItemโดยไม่ต้องเขียนทับ_renderItemต้นแบบปลั๊กอินดั้งเดิม

ในตัวอย่างของฉันยังใช้ฟังก์ชั่นการเรนเดอร์ดั้งเดิมเพื่อลดความซับซ้อนของโค้ด

เป็นสิ่งสำคัญหากคุณต้องการใช้ปลั๊กอินในสถานที่ต่าง ๆ ที่มีมุมมองการเติมข้อความอัตโนมัติที่แตกต่างกันและไม่ต้องการทำลายรหัสของคุณ


โดยทั่วไปแล้วจะเป็นการดีกว่าที่จะใช้เวลาตอบคำถามใหม่หรือตอบคำถามที่ไม่มีคำตอบแทนที่จะตอบคำถามอายุ 6 ปีที่ได้รับคำตอบแล้ว
zchrykng

0

หากคุณใช้ปลั๊กอินของบุคคลที่สามแทนที่จะมีตัวเลือกไฮไลต์: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(ดูแท็บตัวเลือก)


ใช่ฉันตระหนักถึงปลั๊กอินนี้อย่างไรก็ตามเราใช้ jQueryUI ในแอปของเราดังนั้นจึงเป็นการดีที่จะได้ทำงานกับ jQueryUI Autocomplete plug-in
dev.e.loper

1
ตั้งแต่ 2010-06-23, ปลั๊กอิน jQuery Autocomplete ได้รับการสนับสนุนโดยสนับสนุนปลั๊กอิน jQuery UI Autocomplete ดูbassistance.de/jquery-plugins/jquery-plugin-autocompleteสำหรับข้อมูลเพิ่มเติม
shek

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>");
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.