programing

텍스트 영역의 트위터 스타일 자동 완성

javajsp 2023. 3. 20. 21:27

텍스트 영역의 트위터 스타일 자동 완성

다음과 같은 Javascript 자동 완성 구현을 찾고 있습니다.

  • HTML 텍스트 영역에서 사용 가능
  • 자동 완료를 호출하지 않고 일반 텍스트를 입력할 수 있습니다.
  • 를 검출합니다.@문자를 입력하면 자동 완성됩니다.
  • AJAX를 통해 옵션 목록을 로드합니다.

Twitter가 tweet에 태그를 붙일 때 하는 것과 비슷하다고 생각합니다만, 재이용 가능한 좋은 실장은 찾을 수 없습니다.
jQuery를 사용한 솔루션이 좋습니다.

감사해요.

이 문제를 해결하는 또 하나의 훌륭한 라이브러리 At.js(추천)

원천

데모

그들은 지금 트리뷰트 도서관을 제안하고 있다.

https://github.com/zurb/tribute

문제가 해결되려면 한참 걸리겠지만, jquery-textcomplete로 충분할 것 같습니다.

이거 먹어봤어?

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

데모/구성: http://podio.github.io/jquery-mentions-input/

구현은 매우 간단합니다.

이 목적을 위해 Meteor 패키지를 만들었습니다.Meteor의 데이터 모델에서는 커스텀 렌더링 리스트를 사용한 신속한 멀티 룰 검색이 가능합니다.웹 앱에 Meteor를 사용하고 있지 않다면 (아마도) 이렇게 훌륭한 자동 완성 기능을 찾을 수 없을 것입니다.

사용자 자동 완성@여기서 온라인 사용자는 녹색으로 표시됩니다.

여기에 이미지 설명 입력

같은 줄에서 메타데이터 및 부트스트랩 아이콘을 사용하여 다른 작업을 자동으로 완료합니다.

여기에 이미지 설명 입력

포크, 풀, 개선:

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

이것을 시험해 보세요.

(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/ 이 링크는 도움이 됩니다.

요건에 맞는 솔루션을 찾을 수 없었기 때문에 다음과 같은 결과가 나왔습니다.

jQuery를 사용합니다.keypress()사용자가 를 누르고 있는지 확인하기 위한 이벤트@성격.
이 경우 jQuery UI를 사용하여 모달 대화 상자가 표시됩니다.이 대화 상자에는 자동 완성 텍스트 필드가 포함되어 있습니다(많은 옵션을 사용할 수 있지만 jQuery Tokeninput을 권장합니다).
사용자가 대화 상자에서 옵션을 선택하면 텍스트 필드에 태그가 추가되고 대화 상자가 닫힙니다.

이것은 가장 우아한 솔루션은 아니지만 작동하며 원래 디자인에 비해 키를 더 누를 필요가 없습니다.

★★★★★
기본적으로 사용자가 텍스트를 입력할 수 있는 큰 텍스트 상자가 있습니다. 수 있어야 합니다(은 단지 "태그"를 삽입하는 것을 합니다).#<userid>★★★★★★★★★★★★★★★★★★★★★」하여 jQuery를 합니다.@" " 를 한 문자(e.which == 64)태그를 지정할 사용자를 선택하기 위한 텍스트 필드가 있는 모달 표시

이 솔루션의 핵심은 jQuery Tokeninput 텍스트 상자가 있는 이 모달 대화 상자입니다.사용자가 여기에 입력하면 사용자 목록이 AJAX를 통해 로드됩니다.올바르게 사용하는 방법에 대해서는, Web 사이트의 예를 참조해 주세요.사용자가 대화상자를 닫으면 선택한 ID를 큰 텍스트 상자에 삽입합니다.

최근에 나는 이 문제에 직면해야 했고 이렇게 해서 나는...

  1. selectionStart를 사용하여 텍스트 영역의 커서 위치에서 문자열 인덱스를 가져옵니다.
  2. 인덱스 0에서 커서 위치로 문자열을 슬라이스합니다.
  3. 스팬에 삽입(스팬에 여러 개의 테두리 상자가 있으므로)
  4. 뷰 포트를 기준으로 element.getClientRects()를 사용하여 테두리 상자의 치수를 가져옵니다.(여기 MDN 레퍼런스)
  5. 상단 및 왼쪽을 계산하여 드롭다운에 공급합니다.

이 기능은 모든 최신 브라우저에서 작동합니다.오래된 것은 시험해 본 적이 없다

여기 작업함입니다.

유사한 기능을 제공하는 다른 플러그인:

자동 제안

사용자 지정 트리거와 함께 사용하거나 트리거 없이 사용할 수 있습니다.입력 필드, 텍스트 영역 및 컨텐츠 편집 가능 파일과 함께 작동합니다.jQuery는 의존관계가 아닙니다.

플러그인을 추천합니다.jQuery 종속성이 없습니다.필요할 수 있습니다.bootstrap.css참조할 수 있지만, 직접 CSS를 가볍고 간단하게 작성할 것을 권장합니다.

아래 단계에 따라 시험해 보십시오.

  1. npm install @textcomplete/core @textcomplete/textarea
  2. 묶으세요.input 소 element
    const editor = new TextareaEditor(inputEl);
    const textcomplete = new Textcomplete(editor, strategy, options);
    
  3. ★★strategy목록 ) 및 (제안 목록 가져오기 방법)options(어느 쪽인가 하면)

여기에 이미지 설명 입력

JS 버전

각도 버전

이 작은 확장이 적어도 요청한 내용에 가장 가까운 것 같습니다.작기 때문에 쉽게 이해하고 수정할 수 있습니다.http://lookapanda.github.io/jquery-hashtags/

이거면 될 거야.검색을 시작하는 @에 대해서는 가능한 각 검색어의 선두에 기호를 추가합니다(동적인지 여부에 관계없이).

언급URL : https://stackoverflow.com/questions/6157992/twitter-style-autocomplete-in-textarea