2010-07-20 6 views
13

J'ai une zone de texte html qui sera mise à jour périodiquement via javascript.mettre à jour la valeur textarea, mais garder la position du curseur

quand je fais ceci:

$("#textarea").val(new_val); 

Le curseur se déplace vers la fin du texte.

Je voudrais mettre à jour le texte sans changer la position du curseur. En outre, si l'utilisateur a sélectionné une plage de texte, la surbrillance doit être conservée.

Répondre

23

Voici une paire de fonctions qui obtiennent et définissent la position de sélection/caret dans une zone de texte dans tous les principaux navigateurs.

Remarque: si vous n'avez pas besoin de soutenir IE < = 8, il suffit d'utiliser les selectionStart et selectionEnd propriétés (MDN). Tout le code compliqué ci-dessous est juste là pour soutenir les anciennes versions de IE.

function getInputSelection(el) { 
    var start = 0, end = 0, normalizedValue, range, 
     textInputRange, len, endRange; 

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { 
     start = el.selectionStart; 
     end = el.selectionEnd; 
    } else { 
     range = document.selection.createRange(); 

     if (range && range.parentElement() == el) { 
      len = el.value.length; 
      normalizedValue = el.value.replace(/\r\n/g, "\n"); 

      // Create a working TextRange that lives only in the input 
      textInputRange = el.createTextRange(); 
      textInputRange.moveToBookmark(range.getBookmark()); 

      // Check if the start and end of the selection are at the very end 
      // of the input, since moveStart/moveEnd doesn't return what we want 
      // in those cases 
      endRange = el.createTextRange(); 
      endRange.collapse(false); 

      if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { 
       start = end = len; 
      } else { 
       start = -textInputRange.moveStart("character", -len); 
       start += normalizedValue.slice(0, start).split("\n").length - 1; 

       if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { 
        end = len; 
       } else { 
        end = -textInputRange.moveEnd("character", -len); 
        end += normalizedValue.slice(0, end).split("\n").length - 1; 
       } 
      } 
     } 
    } 

    return { 
     start: start, 
     end: end 
    }; 
} 

function offsetToRangeCharacterMove(el, offset) { 
    return offset - (el.value.slice(0, offset).split("\r\n").length - 1); 
} 

function setInputSelection(el, startOffset, endOffset) { 
    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { 
     el.selectionStart = startOffset; 
     el.selectionEnd = endOffset; 
    } else { 
     var range = el.createTextRange(); 
     var startCharMove = offsetToRangeCharacterMove(el, startOffset); 
     range.collapse(true); 
     if (startOffset == endOffset) { 
      range.move("character", startCharMove); 
     } else { 
      range.moveEnd("character", offsetToRangeCharacterMove(el, endOffset)); 
      range.moveStart("character", startCharMove); 
     } 
     range.select(); 
    } 
} 

Lorsque vous modifiez la valeur de la zone de texte, enregistrez d'abord la sélection, puis la restaurer après:

var t = document.getElementById("textarea"); 
var sel = getInputSelection(t); 
t.value = some_new_value; 
setInputSelection(t, sel.start, sel.end); 
+0

Est-ce que le travail de la fonction 'setInputSelection' que dans IE? Je demande parce que la méthode 'createTextRange' n'existe pas (pour les éléments d'entrée) dans les autres navigateurs, de sorte qu'une erreur est levée. –

+0

@ Šime: Oh, oui, désolé. Copier/coller d'une question d'IE seulement Réviser maintenant ... –

+0

@ Šime: ... et fini. –

Questions connexes