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

Posted

技术标签:

【中文标题】如何自定义格式自动完成插件结果?【英文标题】:How can I custom-format the Autocomplete plug-in results? 【发布时间】:2011-01-27 00:23:44 【问题描述】:

我正在使用jQuery UI Autocomplete plug-in。有没有办法在下拉结果中突出显示搜索字符序列?

例如,如果我将“foo bar”作为数据并输入“foo”,我将在下拉菜单中看到“foo bar”,如下所示:

【问题讨论】:

【参考方案1】:

是的,如果你猴子补丁自动完成,你可以。

在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 以产生所需的效果。这种重新定义库中的内部函数的技术,我来学习称为monkey-patching。我是这样做的:

  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,因为:

为列表中呈现的每个项目创建了一个正则表达式 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替换为"$&amp;"即可。


编辑 上述更改每个页面上的自动完成小部件。如果只想改一个,看这个问题:How to patch *just one* instance of Autocomplete on a page?

【讨论】:

谢谢芝士。你有这个的 jsbin 链接吗? 请注意,如果您将事情串联起来,重置上下文很重要:oldFn.apply(this, [ul, item]); 非常感谢!如果这成为 jQuery UI 的一部分,那就太棒了。 我想说的一件事是,如果您希望它在匹配字符串的任何部分(不仅仅是开头)中将结果加粗,请将 RegExp 行修改为: var re = new RegExp(this.术语); JQueryUI 自动完成似乎默认执行不区分大小写的搜索,因此在 RegExp 对象中添加“i”标志是有意义的。正如@DavidRyder 提到的那样,也没有理由在正则表达式中使用“^”。喜欢:var re = new RegExp(this.term, "i"); 很棒的帖子!【参考方案2】:

这也有效:

       $.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 的回复的组合。

【讨论】:

我更喜欢这个,因为它与整个单词匹配。 这很好用。唯一需要注意的是 item.label 正在被替换。对我来说,我的文本框中出现了“ 如果您有一个支持多个值的自动完成,这将不起作用。有什么建议吗? 在自动完成结果中突出显示文本的最简单方法。显然要注意上面 leora 和 Kijana 指出的错误 @RNKushwaha 在您致电$().autocomplete()之前的任何地方【参考方案3】:

超级有用。谢谢你。 +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();

【讨论】:

感谢 Orolo,我在多个位置使用了自动完成功能,并且想要一个中心位置,我可以在其中进行更改以仅显示以键入的字符开头的结果,而这正是我所需要的!跨度> 谢谢。这是最好的解决方案。它适用于不区分大小写。【参考方案4】:

这里是一个功能完整的例子:

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

希望对你有帮助

【讨论】:

【参考方案5】:

jQueryUI 1.9.0 改变了 _renderItem 的工作方式。

下面的代码考虑了这一变化,还展示了我是如何使用 Jörn Zaefferer 的 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();
);

【讨论】:

当我使用像 '(' 这样的字符进行搜索时,它会导致错误 ("Uncaught SyntaxError: Invalid regular expression: /(sam|at|()/: Unterminated group ") 无论如何通过防止与正则表达式冲突? 很棒的答案!喜欢它突出显示的条款,无论它们出现在哪里。很酷。感谢您更新帖子。我确实有一个问题是关于您使用的 .ui-menu-item-highlight 类。这预计将由 jquery-ui 或消费者定义吗?我更改了类名以适应我自己的方式,并简单地将字体粗细设置为粗体。 .jqAutocompleteMatch font-weight: bold; @IdanShechter 很棒的评论。在进行任何处理之前,应该使用一些逻辑来逃避正则表达式的this.term。请参阅 Escape string for use in Javascript regex 作为如何执行此操作的众多答案之一。【参考方案6】:

为了更简单的方法,试试这个:

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

【讨论】:

【参考方案7】:

这里重述了 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);
;

【讨论】:

我认为你在重新发明***!为什么不使用比所有这些代码更快、更简单、更紧凑的正则表达式?【参考方案8】:

这里是一个不需要任何正则表达式并且匹配标签中的多个结果的版本。

$.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 只能区分大小写。 你有什么方法可以根据不区分大小写来匹配单词吗?因为如果我搜索“alfa”,它不会突出显示“Alfa”【参考方案9】:

看看组合框演示,它包括结果突出显示:http://jqueryui.com/demos/autocomplete/#combobox

那里使用的正则表达式也处理 html 结果。

【讨论】:

不再出现(据我所知)【参考方案10】:

这是我的版本:

使用 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);
;

Highlight matched text example

【讨论】:

【参考方案11】:

您可以使用以下代码:

库:

$.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 年的问题。【参考方案12】:

如果您改为使用 3rd 方插件,它有一个突出显示选项: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(参见选项标签)

【讨论】:

是的,我知道这个插件。但是,我们在我们的应用程序中使用了 jQueryUI,所以如果使用 jQueryUI 自动完成插件来实现这个功能会很好 自 2010-06-23 起,jQuery 自动完成插件已被弃用,取而代之的是 jQuery UI 自动完成插件。请参阅bassistance.de/jquery-plugins/jquery-plugin-autocomplete 了解更多信息【参考方案13】:

要支持多个值,只需添加以下函数:

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

【讨论】:

以上是关于如何自定义格式自动完成插件结果?的主要内容,如果未能解决你的问题,请参考以下文章

jQueryUI 自动完成 - 当没有结果返回时

如何自定义自动完成

自定义 jquery 自动完成结果

如何使用选项组重置材料自动完成中的自定义过滤器

如何创建自定义自动完成功能,如内置自动完成功能?

Excel,自定义自动填充功能