如何自定义格式化自动完成插件的结果?


Answers:


233

即时建议自动完成

是的,如果您是自动完成猴子补丁程序,则可以。

在jQuery UI v1.8rc3中包含的自动完成小部件中,建议弹出窗口是在自动完成小部件的_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(...)

现在,这是一个hack,因为:

  • 有一个为列表中呈现的每个项目创建的regexp 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"$&"


编辑
上面的内容更改了页面上的每个自动完成窗口小部件。如果您只想更改一个,请参阅以下问题:
如何仅修补页面上的一个*自动完成实例?


感谢Cheeso。你有jsbin链接吗?
dev.e.loper 2010年

1
请注意,如果您沿链进行操作,则重置上下文很重要:oldFn.apply(this,[ul,item]);
emanaton

非常感谢你!如果这成为jQuery UI的一部分,那就太好了。
David Ryder

4
我要说的一件事是,如果您希望它在匹配字符串的任何部分(而不只是开头)中加粗结果,请将RegExp行修改为:var re = new RegExp(this.term);
大卫·赖德

1
默认情况下,JQueryUI自动完成功能似乎不区分大小写,因此在RegExp对象中添加“ i”标志是有意义的。也没有理由像@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);
        };

@JörnZaefferer和@Cheeso的回应的结合。


我更喜欢这个,因为它与整个单词都匹配。
atp

3
这很好。唯一需要注意的是item.label即将被替换。对我来说,我在文本框中得到“ <strong ...”。只需将替换结果分配给另一个变量就可以清除。如果您的数据包含一个value属性,该属性被放入文本框,则不会有此问题。
基贾纳·伍德雅德(Kijana Woodard)2012年

如果您具有支持多个值的自动填充功能,则此方法不起作用。有什么建议?
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 2012年

谢谢。这是最好的解决方案。它不区分大小写。
Aniket Kulkarni 2013年

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的工作方式。

下面的代码考虑了此更改,还显示了我如何使用JörnZaefferer的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();
});

当我使用类似“(”的字符搜索时,会导致错误(“未捕获的SyntaxError:无效的正则表达式:/(sam | at |()/:未终止的组”))可以通过防止与正则表达式
冲突

很棒的答案!喜欢它突出显示这些术语,无论它们出现在何处。很酷。感谢您更新帖子。我确实有一个问题是关于您使用的.ui-menu-item-highlight类。预期这是由jquery-ui还是由使用者定义的?我将类名更改为适合自己的方式,并仅使字体粗体变为粗体。 .jqAutocompleteMatch { font-weight: bold; }
山姆

@IdanShechter很棒的评论。this.term在执行任何处理之前,应使用一些逻辑来转义for regex。有关如何执行此操作的众多答案之一,请参见在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

这是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
我认为您正在重新发明轮子!为什么不使用比所有这些代码更快,更容易且更紧凑的正则表达式?
乔治·马夫里斯基斯基

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

您有什么方法可以根据不区分大小写的方式匹配单词吗?因为如果我搜索“ alfa”,它将不会突出显示“ Alfa”
Patrick


1

这是我的版本:

  • 使用DOM函数代替RegEx来中断字符串/注入span标签
  • 仅影响指定的自动完成功能,而不是全部
  • 与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

您可以使用以下代码:

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 '16

0

如果您改用第3方插件,则该插件有一个突出显示的选项:http : //docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(请参见“选项”标签)


是的,我知道此插件。但是,我们在应用程序中使用了jQueryUI,因此很高兴将它与jQueryUI Autocomplete插件一起使用
dev.e.loper 2010年

1
自2010年6月23日起,不推荐使用jQuery Autocomplete插件,而推荐使用jQuery UI Autocomplete插件。见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>");
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.