Автозаполнение в стиле Twitter в текстовой области - PullRequest
46 голосов
/ 28 мая 2011

Я ищу реализацию автозаполнения Javascript, которая включает в себя следующее:

  • Может использоваться в текстовой области HTML
  • Позволяет вводить обычный текст без вызова автозаполнения
  • Обнаруживает символ @ и запускает автозаполнение при вводе
  • Загружает список опций через AJAX

Я считаю, что это похоже на то, что делает Twitter при добавлении тегов в твит, но я не могу найти хорошую, многократно используемую реализацию.
Решение с JQuery было бы идеально.

Спасибо.

Ответы [ 10 ]

18 голосов
/ 28 января 2014

Я уверен, что ваша проблема давно решена, но jquery-textcomplete выглядит так, как будто это сработает.

17 голосов
/ 04 марта 2014

Еще одна замечательная библиотека, которая решает эту проблему. At.js

Источник

Демо

7 голосов
/ 11 марта 2014

Вы пробовали это

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

ДЕМО / КОНФИГ: http://podio.github.io/jquery-mentions-input/

Это довольно просто реализовать.

6 голосов
/ 18 июня 2011

Попробуйте это:

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

http://jsfiddle.net/mekwall/mcWnL/52/ Эта ссылка поможет вам

5 голосов
/ 23 сентября 2013

Я создал пакет Meteor для этой цели. Модель данных Meteor позволяет осуществлять быстрый поиск по нескольким правилам с помощью пользовательских списков. Если вы не используете Meteor для своего веб-приложения, (я верю) вы, к сожалению, не найдете ничего удивительного для автозаполнения.

Автозаполнение пользователей с помощью @, где онлайн-пользователи отображаются зеленым цветом:

enter image description here

В той же строке автозаполнение чего-либо еще с метаданными и значками начальной загрузки:

enter image description here

Вилка, тянуть и улучшать:

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

4 голосов
/ 08 июня 2011

Я не смог найти никакого решения, которое бы идеально соответствовало моим требованиям, поэтому я получил следующее:

Я использую событие jQuery keypress(), чтобы проверить, нажимает ли пользователь символ @.
В этом случае модальное диалоговое окно отображается с использованием пользовательского интерфейса jQuery. Этот диалог содержит текстовое поле автозаполнения (здесь можно использовать много опций, но я рекомендую jQuery Tokeninput )
Когда пользователь выбирает параметр в диалоговом окне, в текстовое поле добавляется тег, и диалоговое окно закрывается.

Это не самое элегантное решение, но оно работает и не требует дополнительных нажатий клавиш по сравнению с моим оригинальным дизайном.

Редактировать
В общем, у нас есть большое текстовое поле, в которое пользователь может вводить текст. Он должен иметь возможность «помечать» пользователя (это просто означает вставку #<userid> в текст). Я присоединяюсь к событию keyup jQuery и определяю символ @, используя (e.which == 64), чтобы показать модальное поле с текстовым полем для выбора пользователей для тега.

Суть решения - просто этот модальный диалог с текстовым полем jQuery Tokeninput . Поскольку пользователь вводит здесь, список пользователей загружается через AJAX. Смотрите примеры на сайте, чтобы узнать, как правильно его использовать. Когда пользователь закрывает диалоговое окно, я вставляю выбранные идентификаторы в большое текстовое поле.

3 голосов
/ 27 июня 2013

Недавно мне пришлось столкнуться с этой проблемой, и вот как я прибил ...

  1. Получить индекс строки в позиции курсора в текстовой области, используя selectionStart
  2. sliceстрока от индекса 0 до позиции курсора
  3. Вставьте ее в диапазон (так как диапазон имеет несколько рамок границ)
  4. Получите размеры рамки границ с помощью element.getClientRects () относительнопосмотреть порт.(вот справочник MDN )
  5. Рассчитайте верхний и левый столбцы и введите его в раскрывающийся список

Это работает во всех последних браузерах.не проверял на старых

Вот Рабочая корзина

1 голос
/ 06 января 2019

Еще один плагин, который предоставляет аналогичные функции:

AutoSuggest

Вы можете использовать его с пользовательскими триггерами, или вы можете использовать его без каких-либо триггеров,Работает с полями ввода, текстовыми и contenteditables.И jQuery не является зависимостью.

0 голосов
/ 14 мая 2018

Это небольшое расширение, кажется, ближе всего, по крайней мере, в презентации к тому, о чем спрашивали. Поскольку он маленький, его легко понять и изменить. http://lookapanda.github.io/jquery-hashtags/

0 голосов
/ 01 июня 2011

ЭТО должно работать. Что касается @, запускающего поиск, просто добавьте (динамически или нет) символ в начало каждого возможного поискового запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...