textarea中的Twitter式自动完成

我正在寻找一个Javascript自动完成实现,其中包括以下内容:

  • 可以在HTML textarea中使用
  • 允许在不调用自动完成的情况下input常规文本
  • 检测@字符并在input时启动自动完成
  • 通过AJAX加载选项列表

我相信这与Twitter在Twitter上进行标记时所做的相似,但是我找不到一个很好的,可重用的实现。
jQuery的解决scheme将是完美的。

谢谢。

我相信你的问题早已解决了,但jquery-textcomplete看起来好像能完成这个工作。

另一个伟大的图书馆,解决了这个问题At.js

资源

演示

你有没有尝试过

GITHUB: https : //github.com/podio/jquery-mentions-input

DEMO / CONFIG: http : //podio.github.io/jquery-mentions-input/

实现起来相当简单。

我已经为此创build了Meteor包。 meteor的数据模型允许使用自定义渲染列表进行快速的多规则search。 如果你不使用meteor你的Web应用程序,(我相信),不幸的是你不会find任何这样的自动完成的真棒。

使用@自动完成用户,在线用户显示为绿色:

在这里输入图像说明

在同一行中,使用元数据和引导程序图标自动完成其他内容:

在这里输入图像说明

叉,拉,改善:

https://github.com/mizzao/meteor-autocomplete

我找不到完全符合我的要求的解决scheme,所以我最终得到了以下结果:

我使用jQuery keypress()事件来检查用户是否按@字符。
如果是这种情况,则使用jQuery UI显示模式对话框。 这个对话框包含一个自动完成的文本字段(这里可以使用很多选项,但我build议使用jQuery Tokeninput )
当用户在对话框中select一个选项时,一个标签被添加到文本字段并closures对话框。

这不是最优雅的解决scheme,但它的工作原理,并不需要额外的按键相比,我的原始devise。

编辑
所以基本上,我们有我们的大文本框,用户可以input文本。 他应该能够“标记”用户(这只是在文本中插入#<userid> )。 我附加到jQuery的keyup事件和检测@字符使用(e.which == 64)显示模式与文本字段select用户标记。

该解决scheme的肉只是这个模式对话框与jQuery Tokeninput文本框。 当用户在这里键入时,用户列表通过AJAX加载。 请参阅网站上的示例,了解如何正确使用它。 当用户closures对话框时,我将选定的ID插入到大文本框中。

尝试这个:

 (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", at: "left bottom", 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",tahoma,verdana,arial,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> 

最近我不得不面对这个问题,这是我如何钉下来…

  1. 通过使用selectionStart获取textarea中光标位置的string索引
  2. 从索引0切换到光标位置的string
  3. 将它插入一个跨度(因为跨度有多个边框)
  4. 使用element.getClientRects()相对于视图端口获取边框的尺寸。 (这里是MDN参考 )
  5. 计算顶部和左侧,并将其提供给下拉菜单

这适用于所有最新的浏览器。 没有在旧的testing

这是工作箱

这应该工作。 关于@开始search,只需在每个可能的search词的开头添加(dynamic或不dynamic)符号。