텍스트 영역에서 jQuery 커서 위치 설정


435

jQuery를 사용하여 텍스트 필드에서 커서 위치를 어떻게 설정합니까? 내용이있는 텍스트 필드가 있고 필드에 초점을 맞출 때 사용자 커서를 특정 오프셋에 배치하려고합니다. 코드는 다음과 같아야합니다.

$('#input').focus(function() {
  $(this).setCursorPosition(4);
});

해당 setCursorPosition 함수의 구현은 어떤 모양입니까? abcdefg 컨텐츠가있는 텍스트 필드가있는 경우이 호출로 인해 커서가 abcd ** | ** efg로 배치됩니다.

Java에는 비슷한 기능인 setCaretPosition이 있습니다. 자바 스크립트에 대해 비슷한 방법이 있습니까?

업데이트 : jQuery와 함께 작동하도록 CMS 코드를 다음과 같이 수정했습니다.

new function($) {
  $.fn.setCursorPosition = function(pos) {
    if (this.setSelectionRange) {
      this.setSelectionRange(pos, pos);
    } else if (this.createTextRange) {
      var range = this.createTextRange();
      range.collapse(true);
      if(pos < 0) {
        pos = $(this).val().length + pos;
      }
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  }
}(jQuery);

78
$(this).get(0).setSelectionRange)? 당신은 그것이 정확히 this.setSelectionRange느리고 읽기가 더 어렵다는 것을 알고 있습니까? jQuery는 말 그대로 당신을 위해 아무것도하지 않습니다.
bobince

2
@bobince 주석에 추가하려면 함수는 선택한 각 요소에 대해 반복하고 이것을 반환해야합니다. 올바른 코드가 내 대답에 있습니다.
HRJ

21
@bobince도 실제로 정확하지 않습니다. 'this'는 DOM 노드가 아니라 jQuery 객체입니다. 따라서 $ (this) .get (0) .setSelectionRange는 this.get (0) .setSelectionRange와 동일하지만 this.setSelectionRange와 동일하지 않습니다.
Prestaul

$ (이)가 [0] 빠른 다음 $ (이) 갔지 (0) 인
EminezArtus

완전한 솔루션은이 튜토리얼을 확인하십시오. webdesignpluscode.blogspot.com/2017/05/…
와카 스 알리

답변:


254

두 가지 기능이 있습니다.

function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function setCaretToPos (input, pos) {
  setSelectionRange(input, pos, pos);
}

그런 다음 다음과 같이 setCaretToPos를 사용할 수 있습니다.

setCaretToPos(document.getElementById("YOURINPUT"), 4);

jQuery에서의 사용법을 보여주는 a textarea와 a 모두를 사용한 라이브 예제 input:

2016 년 현재 Chrome, Firefox, IE11, 심지어 IE8에서도 테스트 및 작업했습니다 (마지막 참조 ; 스택 스 니펫은 IE8을 지원하지 않습니다).


3
종료 및 선택 선택 오프셋을 설정하기 때문에 접기 (true)가 필요한 이유는 무엇입니까?
Alexis Wilke

@mareoraft :에 작품 textarea(그리고 input크롬, 파이어 폭스, IE8 및 IE11에 나를 위해).
TJ Crowder

내 스크립트 로이 작업을 수행 할 수없는 것 같습니다. 페이지로드시 빈 텍스트 영역이 있으며 응용 프로그램을 사용할 때 자바 스크립트로 채워집니다. 새 쓰기 (사용 기록) 전에 캐럿을 0으로 반환하고 싶습니다. 문제를 일으키는 동적 데이터입니까? 그렇다면 어떻게 해결할 수 있습니까?
Chris

문자열 리터럴 'character'의 의미는 무엇입니까? 해당 문자열을 사용해야합니까?
Jon Schneider

299

jQuery 솔루션은 다음과 같습니다.

$.fn.selectRange = function(start, end) {
    if(end === undefined) {
        end = start;
    }
    return this.each(function() {
        if('selectionStart' in this) {
            this.selectionStart = start;
            this.selectionEnd = end;
        } else if(this.setSelectionRange) {
            this.setSelectionRange(start, end);
        } else if(this.createTextRange) {
            var range = this.createTextRange();
            range.collapse(true);
            range.moveEnd('character', end);
            range.moveStart('character', start);
            range.select();
        }
    });
};

이것으로 할 수 있습니다

$('#elem').selectRange(3,5); // select a range of text
$('#elem').selectRange(3); // set cursor position

2
@Jesse : Dunno 어떻게되었는지, 나는 보통 4를 사용합니다.
mpen

1
@UberNeet : 제안에 따라 업데이트되었습니다.
mpen

1
@ Enve : 테스트 할 IE 5.5 사본이 없지만 jQuery가 IE 5.5를 지원하지 않기 때문일 수 있습니다 .
mpen

1
@ JaroslavZáruba : 그렇습니다. 그것은. 그러나 이미 jQuery를 사용하고 있다면 작성할 필요 가 없습니다selectRange($('.my_input')[0], 3, 5) . 또한 필요한 경우 어떤 이유로 든 둘 이상의 요소와 함께 작동해야합니다. 순수한 네이티브를 원한다면 CMS 솔루션을 사용하십시오.
mpen

2
$('#elem').focus()깜박이는 커서가 나타나도록 미리 추가해야했습니다 .
mareoraft

37

여기에있는 솔루션은 jQuery 확장 코드를 제외하고는 옳습니다.

확장 기능은 선택한 각 요소를 반복하고 this연결 지원으로 돌아갑니다 . 다음은 올바른 버전 :

$.fn.setCursorPosition = function(pos) {
  this.each(function(index, elem) {
    if (elem.setSelectionRange) {
      elem.setSelectionRange(pos, pos);
    } else if (elem.createTextRange) {
      var range = elem.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  });
  return this;
};

4
각 함수는 jquery 객체를 반환합니다. 실제로 할 수 있습니다 : return this.each(function...)독립형 라인을 제거하십시오.
jhummel

23

나에게 맞는 해결책을 찾았습니다.

$.fn.setCursorPosition = function(position){
    if(this.length == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    if(this.length == 0) return this;
    var input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    this.setCursorPosition(this.val().length);
            return this;
}

이제 다음을 호출하여 포커스를 요소의 끝으로 이동할 수 있습니다.

$(element).focusEnd();

또는 위치를 지정하십시오.

$(element).setCursorPosition(3); // This will focus on the third character.

3
텍스트 영역 요소의 경우 텍스트 this.scrollTop(this[0].scrollHeight);영역이 스크롤되어 삽입 점이 표시되도록 focusEnd가 향상되었습니다 .
Drew

12

이것은 Mac OSX의 Safari 5, jQuery 1.4에서 나를 위해 일했습니다.

$("Selector")[elementIx].selectionStart = desiredStartPos; 
$("Selector")[elementIx].selectionEnd = desiredEndPos;

직접 액세스로 제대로 작동하지는 않았지만 완벽하게 작동했습니다. $ (myID) .prop ( 'selectionStart', 위치); $ (myID) .prop ( 'selectionEnd', 위치);
amdan

9

나는 이것이 매우 오래된 게시물이라는 것을 알고 있지만 jQuery 만 사용하여 업데이트하는 더 간단한 솔루션을 제공해야한다고 생각했습니다.

function getTextCursorPosition(ele) {   
    return ele.prop("selectionStart");
}

function setTextCursorPosition(ele,pos) {
    ele.prop("selectionStart", pos + 1);
    ele.prop("selectionEnd", pos + 1);
}

function insertNewLine(text,cursorPos) {
    var firstSlice = text.slice(0,cursorPos);
    var secondSlice = text.slice(cursorPos);

    var new_text = [firstSlice,"\n",secondSlice].join('');

    return new_text;
}

ctrl-enter를 사용하여 새 줄을 추가하는 방법 (Facebook에서와 같이) :

$('textarea').on('keypress',function(e){
    if (e.keyCode == 13 && !e.ctrlKey) {
        e.preventDefault();
        //do something special here with just pressing Enter
    }else if (e.ctrlKey){
        //If the ctrl key was pressed with the Enter key,
        //then enter a new line break into the text
        var cursorPos = getTextCursorPosition($(this));                

        $(this).val(insertNewLine($(this).val(), cursorPos));
        setTextCursorPosition($(this), cursorPos);
    }
});

나는 비판을 받는다. 감사합니다.

업데이트 :이 솔루션은 정상적인 복사 및 붙여 넣기 기능이 작동하지 않도록합니다 (예 : ctrl-c, ctrl-v).이 부분이 다시 작동하도록 나중에 편집해야합니다. 그렇게하는 방법을 알고 있다면 여기에 의견을 보내 주시면 기꺼이 테스트 해 드리겠습니다. 감사.


7

IE에서 커서를 특정 위치로 이동하면이 코드로 충분합니다.

var range = elt.createTextRange();
range.move('character', pos);
range.select();


7

텍스트 영역에 텍스트를 삽입하기 전에 초점을 설정 하시겠습니까?

$("#comments").focus();
$("#comments").val(comments);

6

이것은 크롬에서 나를 위해 작동합니다

$('#input').focus(function() {
    setTimeout( function() {
        document.getElementById('input').selectionStart = 4;
        document.getElementById('input').selectionEnd = 4;
    }, 1);
});

일반적으로 사용자가 재정의하려는 텍스트 필드의 일부 위치를 클릭하거나 탭을 눌러 텍스트 필드에 초점을 맞추기 때문에 마이크로 초 이상의 지연이 필요하므로 위치가 나올 때까지 기다려야합니다. 사용자가 설정 한 다음 변경하십시오.


엄격 모드에서는 읽기 전용 속성에 할당 할 수 없습니다.
Ivan Rubinson

4

Chrome이 frack을 프릭하기 때문에 화살표 키를 사용하는 경우 함수 호출 직후 false를 반환해야합니다.

{
    document.getElementById('moveto3').setSelectionRange(3,3);
    return false;
}

2
에 대한 모범 사례는 아닙니다 return false;. 당신은 event.preventDefault();대신에 원합니다 . 당신이 거짓을 반환하면, event.stopPropagation()항상 바람직한 것은 아닙니다
Alan H.

4

질문을 바탕으로 텍스트 영역에 줄 바꿈이있을 때 대답은 완벽하게 작동하지 않습니다. 대답은 setSelectionRange를 호출하기 전에 지정한 selectionStart, 지정한 selectionEnd을 조정하는 방법을 설명합니다.

@AVProgrammer가 제안한 솔루션으로 다른 질문에서 adjustOffset을 시도해 보았습니다.

function adjustOffset(el, offset) {
    /* From https://stackoverflow.com/a/8928945/611741 */
    var val = el.value, newOffset = offset;
    if (val.indexOf("\r\n") > -1) {
        var matches = val.replace(/\r\n/g, "\n").slice(0, offset).match(/\n/g);
        newOffset += matches ? matches.length : 0;
    }
    return newOffset;
}

$.fn.setCursorPosition = function(position){
    /* From https://stackoverflow.com/a/7180862/611741 */
    if(this.lengh == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    /* From https://stackoverflow.com/a/7180862/611741 
       modified to fit https://stackoverflow.com/a/8928945/611741 */
    if(this.lengh == 0) return this;
    input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        selectionStart = adjustOffset(input, selectionStart);
        selectionEnd = adjustOffset(input, selectionEnd);
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    /* From https://stackoverflow.com/a/7180862/611741 */
    this.setCursorPosition(this.val().length);
}

4

비트 버킷 에서 찾은 코드를 약간 수정

코드는 이제 2 개의 위치가 주어지면 시작 / 종료 지점을 선택 / 강조 할 수 있습니다. FF / Chrome / IE9 / Opera에서 테스트되고 잘 작동합니다.

$('#field').caret(1, 9);

코드는 아래에 나열되어 있으며 몇 줄만 변경되었습니다.

(function($) {
  $.fn.caret = function(pos) {
    var target = this[0];
    if (arguments.length == 0) { //get
      if (target.selectionStart) { //DOM
        var pos = target.selectionStart;
        return pos > 0 ? pos : 0;
      }
      else if (target.createTextRange) { //IE
        target.focus();
        var range = document.selection.createRange();
        if (range == null)
            return '0';
        var re = target.createTextRange();
        var rc = re.duplicate();
        re.moveToBookmark(range.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
      }
      else return 0;
    }

    //set
    var pos_start = pos;
    var pos_end = pos;

    if (arguments.length > 1) {
        pos_end = arguments[1];
    }

    if (target.setSelectionRange) //DOM
      target.setSelectionRange(pos_start, pos_end);
    else if (target.createTextRange) { //IE
      var range = target.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos_end);
      range.moveStart('character', pos_start);
      range.select();
    }
  }
})(jQuery)

Chrome 39, IE11, Safari 5.1.7에서 실행되지만 Firefox 34에서는 실행되지 않습니다. jsfiddle.net/0t94z82k/6
jbobbins

3

나는 contenteditable 요소와 jQuery를 위해 이것을 작동시켜야했고 누군가가 그것을 사용할 준비가되기를 강하게했다.

$.fn.getCaret = function(n) {
    var d = $(this)[0];
    var s, r;
    r = document.createRange();
    r.selectNodeContents(d);
    s = window.getSelection();
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return s.anchorOffset;
};

$.fn.setCaret = function(n) {
    var d = $(this)[0];
    d.focus();
    var r = document.createRange();
    var s = window.getSelection();
    r.setStart(d.childNodes[0], n);
    r.collapse(true);
    s.removeAllRanges();
    s.addRange(r);
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return this;
};

Usage $(selector).getCaret()는 숫자 오프셋을 반환하고 오프셋을 $(selector).setCaret(num)설정하고 요소에 포커스를 설정합니다.

또한 작은 팁 $(selector).setCaret(num)은 콘솔에서 실행 하면 console.log를 반환하지만 콘솔 창에서 설정되므로 포커스를 시각화하지 않습니다.

최고; D


1

setSelectionRange가 없으면 프로토 타입을 직접 변경할 수 있습니다.

(function() {
    if (!HTMLInputElement.prototype.setSelectionRange) {
        HTMLInputElement.prototype.setSelectionRange = function(start, end) {
            if (this.createTextRange) {
                var range = this.createTextRange();
                this.collapse(true);
                this.moveEnd('character', end);
                this.moveStart('character', start);
                this.select();
            }
        }
    }
})();
document.getElementById("input_tag").setSelectionRange(6, 7);

jsFiddle 링크

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.