文本区域中的Twitter风格的自动完成功能

问题描述

| 我正在寻找Javascript自动完成实现,其中包括以下内容: 可以在HTML文本区域中使用 允许键入常规文本而无需调用自动完成功能 检测“ 0”字符并在键入时开始自动完成 通过AJAX加载选项列表 我相信这与Twitter在推文中添加标签时的操作类似,但是我找不到很好的,可重用的实现。 jQuery的解决方案将是完美的。 谢谢。     

解决方法

        我确定您的问题已经解决了很长时间,但是jquery-textcomplete看起来可以完成任务。     ,        另一个解决这个问题的出色库At.js 资源 演示版     ,        你试过这个了吗 GITHUB:https://github.com/podio/jquery-mentions-input 演示/配置:http://podio.github.io/jquery-mentions-input/ 实现起来非常简单。     ,        尝试这个:
(function($){
    
        $.widget(\"ui.tagging\",{
            // default options
            options: {
                source: [],maxItemDisplay: 3,autosize: true,animateResize: false,animateDuration: 50
            },_create: function() {
                var self = this;
                
                this.activeSearch = false;
                this.searchTerm = \"\";
                this.beginFrom = 0;
    
                this.wrapper = $(\"<div>\")
                    .addClass(\"ui-tagging-wrap\");
                
                this.highlight = $(\"<div></div>\");
                
                this.highlightWrapper = $(\"<span></span>\")
                    .addClass(\"ui-corner-all\");
    
                this.highlightContainer = $(\"<div>\")
                    .addClass(\"ui-tagging-highlight\")
                    .append(this.highlight);
    
                this.meta = $(\"<input>\")
                    .attr(\"type\",\"hidden\")
                    .addClass(\"ui-tagging-meta\");
    
                this.container = $(\"<div></div>\")
                    .width(this.element.width())
                    .insertBefore(this.element)
                    .addClass(\"ui-tagging\")
                    .append(
                        this.highlightContainer,this.element.wrap(this.wrapper).parent(),this.meta
                    );
                
                var initialHeight = this.element.height();
                
                this.element.height(this.element.css(\'lineHeight\'));
                
                this.element.keypress(function(e) {
                    // activate on @
                    if (e.which == 64 && !self.activeSearch) {
                        self.activeSearch = true;
                        self.beginFrom = e.target.selectionStart + 1;
                    }
                    // deactivate on space
                    if (e.which == 32 && self.activeSearch) {
                        self.activeSearch = false;
                    }
                }).bind(\"expand keyup keydown change\",function(e) {
                    var cur = self.highlight.find(\"span\"),val = self.element.val(),prevHeight = self.element.height(),rowHeight = self.element.css(\'lineHeight\'),newHeight = 0;
                    cur.each(function(i) {
                        var s = $(this);
                        val = val.replace(s.text(),$(\"<div>\").append(s).html());
                    });
                    self.highlight.html(val);
                    newHeight = self.element.height(rowHeight)[0].scrollHeight;
                    self.element.height(prevHeight);
                    if (newHeight < initialHeight) {
                        newHeight = initialHeight;
                    }
                    if (!$.browser.mozilla) {
                        if (self.element.css(\'paddingBottom\') || self.element.css(\'paddingTop\')) {
                            var padInt =
                                parseInt(self.element.css(\'paddingBottom\').replace(\'px\',\'\')) + 
                                parseInt(self.element.css(\'paddingTop\').replace(\'px\',\'\'));
                            newHeight -= padInt;
                        }
                    }
                    self.options.animateResize ?
                        self.element.stop(true,true).animate({
                                height: newHeight
                            },self.options.animateDuration) : 
                        self.element.height(newHeight);
                    
                    var widget = self.element.autocomplete(\"widget\");
                        widget.position({
                            my: \"left top\",at: \"left bottom\",of: self.container
                        }).width(self.container.width()-4);
                    
                }).autocomplete({
                    minLength: 0,delay: 0,maxDisplay: this.options.maxItemDisplay,open: function(event,ui) {
                        var widget = $(this).autocomplete(\"widget\");
                        widget.position({
                            my: \"left top\",of: self.container
                        }).width(self.container.width()-4);
                    },source: function(request,response) {
                        if (self.activeSearch) {
                            self.searchTerm = request.term.substring(self.beginFrom); 
                            if (request.term.substring(self.beginFrom - 1,self.beginFrom) != \"@\") {
                                self.activeSearch = false;
                                self.beginFrom = 0;
                                self.searchTerm = \"\";
                            }
                            if (self.searchTerm != \"\") {
                                
                                if ($.type(self.options.source) == \"function\") {
                                    self.options.source(request,response);                   
                                } else {
                                    var re = new RegExp(\"^\" + escape(self.searchTerm) + \".+\",\"i\");
                                    var matches = [];
                                    $.each(self.options.source,function() {
                                        if (this.label.match(re)) {
                                            matches.push(this);
                                        }
                                    });
                                    response(matches);
                                }
                            }
                        }
                    },focus: function() {
                        // prevent value inserted on focus
                        return false;
                    },select: function(event,ui) {
                        self.activeSearch = false;
                        //console.log(\"@\"+searchTerm,ui.item.label);
                        this.value = this.value.replace(\"@\" + self.searchTerm,ui.item.label) + \' \';
                        self.highlight.html(
                            self.highlight.html()
                                .replace(\"@\" + self.searchTerm,$(\"<div>\").append(
                                             self.highlightWrapper
                                                 .text(ui.item.label)
                                                 .clone()
                                         ).html()+\' \')
                        );
                            
                        self.meta.val((self.meta.val() + \" @[\" + ui.item.value + \":]\").trim());
                        return false;
                    }
                });
    
            }
        });
body,html {
        font-family: \"lucida grande\",tahoma,verdana,arial,sans-serif;
    }
    
    .ui-tagging {
        position: relative;
        border: 1px solid #B4BBCD;
        height: auto;
    }
    
    .ui-tagging .ui-tagging-highlight {
        position: absolute;
        padding: 5px;
        overflow: hidden;
    }
    .ui-tagging .ui-tagging-highlight div {
        color: transparent;
        font-size: 13px;
        line-height: 18px;
        white-space: pre-wrap;
    }
    
    .ui-tagging .ui-tagging-wrap {
        position: relative;
        padding: 5px;
        overflow: hidden;
        zoom: 1;
        border: 0;
    }
    
    .ui-tagging div > span {
        background-color: #D8DFEA;
        font-weight: normal !important;
    }
    
    .ui-tagging textarea {
        display: block;
        font-family: \"lucida grande\",sans-serif;
        background: transparent;
        border-width: 0;
        font-size: 13px;
        height: 18px;
        outline: none;
        resize: none;
        vertical-align: top;
        width: 100%;
        line-height: 18px;
        overflow: hidden;
    }
    
    .ui-autocomplete {
        font-size: 13px;
        background-color: white;
        border: 1px solid black;
        margin-bottom: -5px;
        width: 0;
    }
<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js\"></script>
<textarea></textarea>
,        为此,我创建了一个Meteor程序包。流星的数据模型允许使用自定义呈现列表快速进行多规则搜索。如果您不打算将Meteor用于您的Web应用程序,那么(我相信)您将不会找到任何如此出色的自动完成功能。 使用“ 0”自动填充用户,其中在线用户以绿色显示: 在同一行中,使用元数据和引导程序图标自动完成其他操作: 叉,拉和改善:   https://github.com/mizzao/meteor-autocomplete     ,        我找不到任何完全符合我的要求的解决方案,因此得到了以下结果: 我使用jQuery
keypress()
事件检查用户是否按
@
字符。 在这种情况下,将使用jQuery UI显示模式对话框。此对话框包含一个自动完成文本字段(此处可以使用许多选项,但我建议使用jQuery Tokeninput) 当用户在对话框中选择一个选项时,会将标签添加到文本字段,然后关闭对话框。 这不是最优雅的解决方案,但它可以工作,并且与我的原始设计相比,不需要额外的按键。 编辑 因此,基本上,我们有了我们的大文本框,用户可以在其中输入文本。他应该能够“标记”用户(这仅意味着在文本中插入“ 7”)。我附加到jQuery keyup事件,并使用
(e.which == 64)
检测
@
字符以显示带有文本字段的模式,以选择要标记的用户。 解决方案的实质就是带有jQuery Tokeninput文本框的模式对话框。当用户在此处键入时,将通过AJAX加载用户列表。有关如何正确使用它,请参见网站上的示例。当用户关闭对话框时,我将选定的ID插入大文本框中。     ,        最近,我不得不面对这个问题,这就是我确定的问题... 通过使用selectionStart获取文本区域中光标位置的字符串索引 将字符串从索引0切到光标位置 将其插入跨度(因为跨度具有多个边框) 使用element.getClientRects()相对于视口获取边框的尺寸。 (这是MDN参考) 计算顶部和左侧并将其馈入下拉菜单 在所有最新的浏览器中都可以使用。没有测试过旧的 这是工作箱     ,        另一个提供类似功能的插件: 自动建议 您可以将其与自定义触发器一起使用,也可以将其与任何触发器一起使用。与输入字段,文本区域和contenteditables一起使用。 jQuery不是依赖项。     ,        这个小扩展似乎至少在外观上与要求的最接近。由于它很小,因此很容易理解和修改。 http://lookapanda.github.io/jquery-hashtags/     ,        这应该工作。关于@开始搜索,只需在每个可能的搜索词的开头添加(动态地或不动态地)符号即可。