Come impostare la posizione del cursore (cursore) nell’elemento contenteditable (div)?

Ho questo semplice HTML come esempio:

text text text
text text text
text text text

Voglio una cosa semplice: quando clicco sul pulsante, voglio posizionare il cursore (cursore) in una posizione specifica nel div editabile. Dalla ricerca sul Web, ho questo JS collegato al clic del pulsante, ma non funziona (FF, Chrome):

 var range = document.createRange(); var myDiv = document.getElementById("editable"); range.setStart(myDiv, 5); range.setEnd(myDiv, 5); 

È ansible impostare manualmente la posizione del cursore come in questo caso?

Nella maggior parte dei browser, hai bisogno degli oggetti Range e Selection . Specificare ciascuno dei limiti di selezione come nodo e offset all’interno di quel nodo. Ad esempio, per impostare il punto di inserimento sul quinto carattere della seconda riga di testo, procedere come segue:

 var el = document.getElementById("editable"); var range = document.createRange(); var sel = window.getSelection(); range.setStart(el.childNodes[2], 5); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); 

IE <9 funziona in modo completamente diverso. Se hai bisogno di supportare questi browser, avrai bisogno di un codice diverso.

Esempio jsFiddle: http://jsfiddle.net/timdown/vXnCM/

La maggior parte delle risposte che trovi sul posizionamento contenteditable del cursore sono abbastanza semplici in quanto soddisfano solo gli input con testo in chiaro. Una volta che si utilizzano elementi html all’interno del contenitore, il testo inserito viene diviso in nodes e distribuito liberamente attraverso una struttura ad albero.

Per impostare la posizione del cursore, ho questa funzione che circonda tutti i nodes di testo figlio all’interno del nodo fornito e imposta un intervallo dall’inizio del nodo iniziale al carattere chars.count :

 function createRange(node, chars, range) { if (!range) { range = document.createRange() range.selectNode(node); range.setStart(node, 0); } if (chars.count === 0) { range.setEnd(node, chars.count); } else if (node && chars.count >0) { if (node.nodeType === Node.TEXT_NODE) { if (node.textContent.length < chars.count) { chars.count -= node.textContent.length; } else { range.setEnd(node, chars.count); chars.count = 0; } } else { for (var lp = 0; lp < node.childNodes.length; lp++) { range = createRange(node.childNodes[lp], chars, range); if (chars.count === 0) { break; } } } } return range; }; 

Quindi chiamo la routine con questa funzione:

 function setCurrentCursorPosition(chars) { if (chars >= 0) { var selection = window.getSelection(); range = createRange(document.getElementById("test").parentNode, { count: chars }); if (range) { range.collapse(false); selection.removeAllRanges(); selection.addRange(range); } } }; 

Il range.collapse (false) imposta il cursore alla fine dell'intervallo. L'ho provato con le ultime versioni di Chrome, IE, Mozilla e Opera e funzionano tutti bene.

PS. Se qualcuno è interessato, ottengo la posizione corrente del cursore usando questo codice:

 function isChildOf(node, parentId) { while (node !== null) { if (node.id === parentId) { return true; } node = node.parentNode; } return false; }; function getCurrentCursorPosition(parentId) { var selection = window.getSelection(), charCount = -1, node; if (selection.focusNode) { if (isChildOf(selection.focusNode, parentId)) { node = selection.focusNode; charCount = selection.focusOffset; while (node) { if (node.id === parentId) { break; } if (node.previousSibling) { node = node.previousSibling; charCount += node.textContent.length; } else { node = node.parentNode; if (node === null) { break } } } } } return charCount; }; 

Il codice fa l'opposto della funzione set: ottiene l'attuale window.getSelection (). FocusNode e focusOffset e conta all'indietro tutti i caratteri di testo rilevati finché non raggiunge un nodo genitore con id di containerId. La funzione isChildOf controlla solo prima di eseguire che il nodo in questione sia in realtà un figlio del parentId fornito.

Il codice dovrebbe funzionare senza modifiche, ma l'ho appena preso da un plugin jQuery che ho sviluppato, quindi ho eliminato un paio di questi - fammi sapere se qualcosa non funziona!

È molto difficile impostare il punto di inserimento nella posizione corretta quando si dispone di un elemento avanzato come (p) (span) ecc. L’objective è ottenere (testo object):

  
dddddddddddddddddddddddddddd

dd

psss

dd

dd

text text text

Se non vuoi usare jQuery puoi provare questo approccio:

 public setCaretPosition() { const editableDiv = document.getElementById('contenteditablediv'); const lastLine = this.input.nativeElement.innerHTML.replace(/.*?(
)/g, ''); const selection = window.getSelection(); selection.collapse(editableDiv.childNodes[editableDiv.childNodes.length - 1], lastLine.length); }

editableDiv è un elemento modificabile, non dimenticare di impostare un id per esso. Quindi devi ottenere il tuo innerHTML dall’elemento e tagliare tutte le linee dei freni. E basta collassare con gli argomenti successivi.