hoşnut, metnin sonunda imleci ayarla (tarayıcılar arası)


111

Chrome'da çıktı :

<div id="content" contenteditable="true" style="border:1px solid #000;width:500px;height:40px;">
    hey
    <div>what's up?</div>
<div>
<button id="insert_caret"></button>

FF'ye şunun gibi görüneceğine inanıyorum :

hey
<br />
what's up?

ve IE'de :

hey
<p>what's up?</p>

ne yazık ki, bunu yapmanın güzel bir yolu yok, böylece her tarayıcı <br />bir div- veya p-etiketi yerine a ekliyor, ya da en azından çevrimiçi hiçbir şey bulamadım.


HER ZAMAN, şimdi yapmaya çalıştığım şey, düğmeye bastığımda imlecin metnin sonuna yerleştirilmesini istiyorum, bu yüzden şuna benzer bir şeye benzemeli:

hey
what's up?|

bunu tüm tarayıcılarda çalışması için yapmanın bir yolu var mı?

misal:

$(document).ready(function()
{
    $('#insert_caret').click(function()
    {
        var ele = $('#content');
        var length = ele.html().length;

        ele.focus();

        //set caret -> end pos
     }
 }

Yanıtlar:


282

Aşağıdaki işlev, tüm büyük tarayıcılarda bunu yapacaktır:

function placeCaretAtEnd(el) {
    el.focus();
    if (typeof window.getSelection != "undefined"
            && typeof document.createRange != "undefined") {
        var range = document.createRange();
        range.selectNodeContents(el);
        range.collapse(false);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (typeof document.body.createTextRange != "undefined") {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(false);
        textRange.select();
    }
}

placeCaretAtEnd( document.querySelector('p') );
p{ padding:.5em; border:1px solid black; }
<p contentEditable>foo bar </p>

İmleci başlangıca yerleştirmek neredeyse aynıdır: Sadece çağrılara aktarılan Boolean'ın değiştirilmesini gerektirir collapse(). İmleci başlangıca ve sona yerleştirmek için işlevler oluşturan bir örnek:

function createCaretPlacer(atStart) {
    return function(el) {
        el.focus();
        if (typeof window.getSelection != "undefined"
                && typeof document.createRange != "undefined") {
            var range = document.createRange();
            range.selectNodeContents(el);
            range.collapse(atStart);
            var sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (typeof document.body.createTextRange != "undefined") {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.collapse(atStart);
            textRange.select();
        }
    };
}

var placeCaretAtStart = createCaretPlacer(true);
var placeCaretAtEnd = createCaretPlacer(false);

CreateTextRange standart bir işlev olmadığı için Chrome ile çalışmaz. Stackoverflow.com/a/41743191/700206 adresine bakın .
whitneyland

@Lee: window.getSelectionve destekleyen Chrome'da iyi çalışıyor document.createRange. createTextRangeŞube Internet Explorer'ın eski sürümleri içindir.
Tim Down

yazma window.getSelectionsırasında tüm tarayıcıların% 0,29'u tarafından desteklenmemektedir (IE> 8). bkz: caniuse.com/#search=window.getSelection
w.stoettinger

@TimDown bu çalışır. +1. Ancak kodu yorum ekleyerek de açıklayabilir misiniz lütfen? Harika olurdu
shinobi

Bir iframe> body öğesini hedeflemeye çalışırken imleci sona nasıl ayarlayacağını (bu kodu kullanın) bilen var mı? Vücut elemanında editablecontent="true"...? placeCaretAtEnd(this);benim için çalışmayacak.
RobbTe

6

Ne yazık ki Tim'in mükemmel cevabı benim için sadece sonuna yerleştirmek için işe yaradı, başlangıca yerleştirmek için biraz değiştirmek zorunda kaldım.

function setCaret(target, isStart) {
  const range = document.createRange();
  const sel = window.getSelection();
  if (isStart){
    const newText = document.createTextNode('');
    target.appendChild(newText);
    range.setStart(target.childNodes[0], 0);
  }
  else {
    range.selectNodeContents(target);
  }
  range.collapse(isStart);
  sel.removeAllRanges();
  sel.addRange(range);
  target.focus();
  target.select();
}

Olmadığından emin değil misiniz olsa focus()ve select()aslında ihtiyaç vardır.


Ayrıca harici bir kitaplık da tanıttınız. Odaklanmanın ve seçmenin gerekli olduğunu düşünmüyorsanız, neden satırları yorumlayıp test etmiyorsunuz?
dotnethaggis

Teşekkürler, jquery kaldırıldı. Bazı çelişkili sonuçlar aldığımı hatırlıyorum, onları tekrar izole etmeye çalışacağım.
dimid

1

Bu (canlı) örnek, setCaretAtStartEndiki bağımsız değişken alan kısa ve basit bir işlevi gösterir ; İmleci yerleştirmek için (düzenlenebilir) bir düğüm ve nereye yerleştirileceğini belirten bir Boolean (düğümün başlangıcı veya sonu)

const editableElm = document.querySelector('[contenteditable]');

document.querySelectorAll('button').forEach((elm, idx) => 
  elm.addEventListener('click', () => {
    editableElm.focus()
    setCaretAtStartEnd(editableElm, idx) 
  })
)

function setCaretAtStartEnd( node, atEnd ){
  const sel = document.getSelection();
  node = node.firstChild;

  if( sel.rangeCount ){
      ['Start', 'End'].forEach(pos =>
        sel.getRangeAt(0)["set" + pos](node, atEnd ? node.length : 0)
      )
  }
}
[contenteditable]{ padding:5px; border:1px solid; }
<h1 contenteditable>Place the caret anywhere</h1>
<br>
<button>Move caret to start</button>
<button>Move caret to end</button>


-1

Google kapatma derleyicisini kullanıyorsanız, aşağıdakileri yapabilirsiniz (Tim'in cevabından biraz basitleştirilmiştir):

function placeCaretAtEnd(el) {
    el.focus();
    range = goog.dom.Range.createFromNodeContents(el);
    range.collapse(false);
    range.select();
}

ClojureScript'te aynı şey:

(defn place-caret-at-end [el] 
   (.focus el)
   (doto (.createFromNodeContents goog.dom.Range el)
         (.collapse false)
         .select))

Bunu Chrome, Safari ve FireFox'ta test ettim, IE hakkında emin değilim ...


1
range = goog.dom.Range.createFromNodeContents (el); goog.dom nedir?
Anh Tú

Bu benim için çalıştı. @ AnhTú: goog.dom, closure-library tarafından sağlanan bir ad alanıdır.
David Beneš
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.