按下TAB时自动完成用户名

时间:2016-10-28 10:13:50

标签: javascript jquery autocomplete

我正在处理“按下TAB时自动完成用户名”功能。

我已经能够检测到var userlist = ['bonjour', 'bleuet', 'bonobo', 'coucou']; function getCaretPosition(ctrl) { var start, end; if (ctrl.setSelectionRange) { start = ctrl.selectionStart; end = ctrl.selectionEnd; } else if (document.selection && document.selection.createRange) { var range = document.selection.createRange(); start = 0 - range.duplicate().moveStart('character', -100000); end = start + range.text.length; } return { start: start, end: end } } $('#writing').keydown(function(e) { if (e.keyCode == 9) { var caret = getCaretPosition(this); var word = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end))); word = word ? word[0] : null; if (word.charAt(0) === '@') alert(userlist.filter((x) => x.indexOf(word.slice(1)) === 0)); e.preventDefault(); return false; } });并搜索用户名列表。

现在如何使用不同的匹配用户名执行自动完成,每次按 TAB

#writing { width: 500px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="writing">Hello @b what's up? hello @you as well... Type @b and then "TAB" key it should autocomplete usernames 
</textarea>
<context:property-placeholder ignore-resource-not-found="true" ignore-unresolvable="true" location="classpath*:/*.local.properties" />
<context:property-placeholder location="classpath:/config.properties" />

3 个答案:

答案 0 :(得分:2)

以下是您的问题的解决方案:

我使用.on()将keydown绑定到textbox,而不是keypress。

var userlist = ['bonjour', 'bleuet', 'bonobo', 'coucou'];

function getCaretPosition(ctrl) {
    var start, end;
    if (ctrl.setSelectionRange) {
        start = ctrl.selectionStart;
        end = ctrl.selectionEnd;
    } else if (document.selection && document.selection.createRange) {
        var range = document.selection.createRange();
        start = 0 - range.duplicate().moveStart('character', -100000);
        end = start + range.text.length;
    }
    return {
        start: start,
        end: end
    }
}

$('#writing').keydown(function(e) {
    if (e.keyCode == 9) {
      var caret = getCaretPosition(this);
      var word = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end)));
      word = word ? word[0] : null;
      if (word.charAt(0) === '@') 
        //alert(userlist.filter((x) => x.indexOf(word.slice(1)) === 0));
        var stringParts = $(this).val().split('@');
        var nameToInsert = userlist.filter((x) => x.indexOf(word.slice(1)) === 0)[0];
        var completeString = stringParts[0] + '@' + nameToInsert;
        $(this).val(completeString);
      e.preventDefault();  
      return false;
    }

    });
#writing { width: 500px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="writing">Hello @b what's up? hello @you as well... Type @b and then "TAB" key it should autocomplete usernames 
</textarea>

现在它完成了名称。但我会努力改进预测名称的算法。

答案 1 :(得分:1)

用keydown替换keypress。当按下标签时Keypress不会触发,我猜因为标签输入没有焦点。

编辑:

不完美,有时会被定义,但你可以在这里工作

编辑: 好吧不要介意这一点,它完成了一半,@ slikts解决方案显然更好,从头开始制作。

var userlist = ['bonjour', 'bleuet', 'bonobo', 'coucou'];
    
    function getCaretPosition(ctrl) {
        var start, end;
        if (ctrl.setSelectionRange) {
            start = ctrl.selectionStart;
            end = ctrl.selectionEnd;
        } else if (document.selection && document.selection.createRange) {
            var range = document.selection.createRange();
            start = 0 - range.duplicate().moveStart('character', -100000);
            end = start + range.text.length;
        }
        return {
            start: start,
            end: end
        }
    }
    function setCaretPosition(elem, caretPos, caretPosEnd) {
        caretPosEnd = caretPosEnd || caretPos;
        if(elem != null) {
            if(elem.createTextRange) {
                var range = elem.createTextRange();
                range.move('character', caretPos);
                range.select();
            }
            else {
                if(elem.selectionStart) {
                    elem.focus();
                    elem.setSelectionRange(caretPos, caretPosEnd);
                }
                else
                    elem.focus();
            }
        }
    }
function getIndexCloserTo(str, char, ref) {  
    if(str.indexOf(char) == -1) return false;
   //flip string and find char beggining from reference point
   var nstr = str.split("").reverse().join("");
   return str.length - 1 - nstr.indexOf(char, str.length - 1 - ref);
}
    var lastWordToMatch = "";
    var lastAddedWord = "";
    var lastIndexUsed = 0;
    $(document).ready( function() {
    	$('#writing').keydown(function(e) {
    	
          if (e.keyCode == 9) {
    			var caret = getCaretPosition(this);
                //Get username input part, from the "@" closer to the cursor
                //to the position of the cursor
                var beginning = getIndexCloserTo(this.value, '@', caret.start);
                if( beginning !== false){
    			var word = this.value.slice( beginning , caret.start);
    			word = word ? word[0] : null;
    			if (word.charAt(0) === '@'){ 
                    //Get array of names that match what is written after the @
    				var usermatches = userlist.filter((x) => x.indexOf(word.slice(1)) === 0);
                    //Check if any matches were found
                    if( usermatches.length > 0 ){
                      //If the word is the same as last time, use the next match
    				  if( word == lastWordToMatch ){
                          //use mod to circle back to beginning of array
    					  index = (lastIndexUsed + 1 ) % usermatches.length;
    					  lastIndexUsed = index;
    				  } else {
                        //otherwise get first match
    					  index = 0; 
    					  lastWordToMatch = word;
    				  }
                      var text = this.value;
                      //Remove @
                      word = word.slice(1);
                      //replace the portion of the word written by the user plus the 
                      //word added by autocompletion, with the match
    				  $(this).val(text.replace(word+lastAddedWord, usermatches[index]) );
                      //save the replacement for the previous step, without the user input
                      //just what autocompetion added
                      lastAddedWord = usermatches[index].replace(word, '');
                      //put cursor back where it was
    				  setCaretPosition(this,caret.start);		
                    }
    			}
                 }
    		  e.preventDefault();  
    		  return false;
    		}
    
    		});
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="writing">Hello @b what's up? hello @you as well... Type @b and then "TAB" key it should autocomplete usernames 
</textarea>

答案 2 :(得分:1)

这是一个非常基本的示例,适用于现代浏览器(Chrome,Firefox,Edge):

const users = ['asdasd', 'fgsfds', 'Foobar']
const input = document.getElementById('input')
const patt = /\S+$/

input.addEventListener('keydown', e => {
  if (e.key !== 'Tab') {
    return
  }
  e.preventDefault()
  const start = input.selectionStart
  const seg = input.value.slice(0, start)
  const match = (seg.match(patt) || [])[0]
  if (!match) {
    return
  }
  const idx = users.findIndex(x => x.startsWith(match))
  if (idx < 0) {
    return
  }
  const replace = users[users[idx] === match ? (idx + 1) % users.length : idx]
  const newSeg = seg.replace(patt, replace)
  input.value = newSeg + input.value.slice(start)
  input.setSelectionRange(newSeg.length, newSeg.length)
})
<input type="text" id="input" size="50" value="bla asd bla fgs">

它循环显示名称并在该行的任何位置工作。可以使用Babel和es6-shim添加对旧版浏览器的支持。