jQuery Metin Alanında İmleç Konumunu Ayarla


435

JQuery kullanarak bir metin alanındaki imleç konumunu nasıl ayarlarsınız? İçeriği olan bir metin alanım var ve kullanıcıların imlecin alana odaklandıklarında belirli bir uzaklıkta konumlandırılmasını istiyorum. Kod şöyle görünmelidir:

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

Bu setCursorPosition işlevinin uygulanması neye benzer? Abcdefg içeriğine sahip bir metin alanınız varsa, bu çağrı imlecin şu şekilde konumlandırılmasına neden olur: abcd ** | ** efg.

Java'nın setCaretPosition benzeri bir işlevi vardır. Javascript için benzer bir yöntem var mı?

Güncelleme: CMS kodunu jQuery ile çalışacak şekilde değiştirdim:

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)? Bunun tam olarak aynı olduğunu biliyorsun this.setSelectionRange, sadece daha yavaş ve okunması zor, değil mi? jQuery burada sizin için hiçbir şey yapmıyor.
bobince

2
@Bobince yorumuna eklemek için işlev, seçilen öğelerin her biri için yinelenmeli ve bunu döndürmelidir. Cevabımda doğru kod var.
HRJ

21
@bobince aslında tam olarak doğru değil. 'this' DOM düğümü değil, jQuery nesnesidir. Yani, $ (this) .get (0) .setSelectionRange this.get (0) .setSelectionRange ile aynıdır, this.setSelectionRange ile aynı değildir.
Prestaul

$ (this) [0] $ (this) 'dan daha hızlıdır.
get

Tam çözüm için bu eğiticiye göz atın. webdesignpluscode.blogspot.com/2017/05/…
Waqas Ali

Yanıtlar:


254

İki fonksiyonum var:

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);
}

Sonra setCaretToPos'u şu şekilde kullanabilirsiniz:

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

JQuery kullanımını gösteren a textareave an ile canlı örnek input:

2016 itibariyle, Chrome, Firefox, IE11, hatta IE8 üzerinde test edildi ve çalışıyor ( burada sonuncuya bakın ; Yığın Parçacıkları IE8'i desteklemiyor).


3
Sonu ve seçim ofsetlerini ayarlayacağınız için neden daraltma (true) gereklidir?
Alexis Wilke

@mareoraft: Benim için textarea(ve input) Chrome, Firefox, IE8 ve IE11'de çalışır.
TJ Crowder

Senaryomla çalışmak için bunu elde edemiyorum. Sayfa yükleme boş, sonra uygulama kullanılırken javascript tarafından doldurulmuş bir metin alanı var. Her yeni yazma işleminden önce kullanımın 0'a döndürülmesini istiyorum (kullanımın kaydı). sorun yaratan dinamik veriler mi? eğer öyleyse bunu nasıl çözebilirim?
Chris

Dize değişmez 'karakterinin' önemi nedir? Bu özel dizenin kullanılması gerekiyor mu?
Jon Schneider

299

İşte bir jQuery çözümü:

$.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();
        }
    });
};

Bununla yapabilirsin

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

2
@Jesse: Bunun nasıl olduğunu bilmiyorum, genellikle 4 kullanıyorum. Sabit.
49'da mpen

1
@UberNeet: Öneriye göre güncellendi.
mpen

1
@Enve: Test etmek için IE 5.5'in bir kopyasına sahip değilim, ancak jQuery IE 5.5'i desteklemiyor olabilir .
mpen

1
@ JaroslavZáruba: Evet. Bu. Ama sağlar değil yazma zorunda selectRange($('.my_input')[0], 3, 5)zaten jQuery kullanıyorsanız. Ayrıca, herhangi bir nedenden dolayı, eğer ihtiyacınız varsa, birden fazla elemanla çalışmalıdır. Saf yerel istiyorsanız, lütfen CMS'nin çözümünü kullanın.
mpen

2
$('#elem').focus()Yanıp sönen imlecin görünmesi için önceden eklemem gerekiyordu.
mareoraft

37

Buradaki çözümler jQuery uzantı kodu dışında doğrudur.

Eklenti işlevi, seçilen her öğe üzerinde yinelenmeli ve thisdestek zincirine dönmelidir . İşte bir doğru sürümü:

$.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
Her işlev jquery nesnesini döndürür. böylece şunları yapabilirsiniz: return this.each(function...)ve bağımsız satırı kaldırın.
jhummel

23

Benim için çalışan bir çözüm buldum:

$.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;
}

Artık odağı herhangi bir öğenin sonuna taşıyarak şunları çağırabilirsiniz:

$(element).focusEnd();

Veya konumu belirtirsiniz.

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

3
Metin alanı öğeleri için, this.scrollTop(this[0].scrollHeight);metin noktasını ekleme noktasını görünür kılmak üzere kaydırıldığından emin olmak için focusEnd öğesine bir iyileştirme eklenecektir .
Drew

12

Bu benim için Mac OSX, jQuery 1.4 Safari 5 üzerinde çalıştı:

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

benim için doğrudan erişim ile iyi çalışmıyor, ama bu mükemmel çalıştı. $ (myID) .prop ('selectionStart', konum); $ (myID) .prop ('selectionEnd', konum);
amdan

9

Bunun çok eski bir yazı olduğunu anlıyorum, ancak sadece jQuery kullanarak güncellemek için belki de daha basit bir çözüm sunmam gerektiğini düşündüm.

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;
}

Yeni bir satır eklemek için ctrl-enter kullanımı (Facebook'ta olduğu gibi):

$('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);
    }
});

Eleştiriye açıkım. Teşekkür ederim.

GÜNCELLEME: Bu çözüm, normal kopyalama ve yapıştırma işlevlerinin çalışmasına izin vermez (yani ctrl-c, ctrl-v), bu nedenle gelecekte parçanın tekrar çalıştığından emin olmak için bunu düzenlemem gerekecek. Bunu nasıl yapacağınız hakkında bir fikriniz varsa, lütfen buraya yorum yapın, test etmekten mutluluk duyarız. Teşekkürler.


7

IE'de imleci belirli bir konuma taşımak için bu kod yeterlidir:

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


7

Metni metin alanına eklemeden önce odağı ayarlayın?

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

6

Bu benim için kromda çalışıyor

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

Görünüşe göre mikrosaniye veya daha fazla bir gecikmeye ihtiyacınız var, çünkü genellikle bir kullanıcı, geçersiz kılmak istediğiniz metin alanında (veya sekmeye basarak) bir konuma tıklayarak metin alanına odaklanır, böylece konumun kullanıcı tarafından ayarlanır tıklayıp değiştirin.


Katı modda salt okunur özelliklere
atamaya

4

Chrome, aksi halde dolandırıcılığı ateşlediğinden, ok tuşlarını kullanıyorsanız, işlev çağrısından hemen sonra false değerini döndürmeyi unutmayın.

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

2
En iyi uygulama bu değil return false;. Bunun event.preventDefault();yerine istiyorsun . Yanlış döndürürseniz, event.stopPropagation()hangisinin her zaman arzu edilmediğini ima edersiniz
Alan H.

4

Bu soruya dayanarak , cevap textarea'da yeni bir çizgi olduğunda ie ve opera için mükemmel çalışmayacaktır. Cevap setSelectionRange çağırmadan önce SelectionStart, selectionEnd nasıl ayarlanacağını açıklar.

@AVProgrammer tarafından önerilen çözüm ile diğer sorudan adjustOffset denedim ve işe yarıyor.

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

Bitbucket'te bulduğum kodda küçük değişiklik

Kod artık 2 konum verilirse başlangıç ​​/ bitiş noktaları ile seçebilir / vurgulayabilir. FF / Chrome / IE9 / Opera'da test edildi ve iyi çalışıyor.

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

Kod aşağıda listelenmiştir, yalnızca birkaç satır değişmiştir:

(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'de çalışıyor ancak Firefox 34'te çalışmıyor
jbobbins

3

Bu çalışılabilir içerikler ve jQuery için çalışmak zorunda kaldı ve birinin kullanıma hazır isteyebilir düşündüm:

$.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;
};

Kullanım $(selector).getCaret()sayı ofsetini döndürür ve ofseti $(selector).setCaret(num)belirler ve öğeye odaklamayı ayarlar.

Ayrıca küçük bir ipucu, $(selector).setCaret(num)konsoldan çalıştırırsanız console.log döndürür, ancak konsol penceresinde kurulduğundan odağı görselleştirmezsiniz.

En iyiler; D


1

SetSelectionRange yoksa prototipi doğrudan değiştirebilirsiniz.

(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 bağlantısı

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.