代码之家  ›  专栏  ›  技术社区  ›  Ben Noland

更新textarea值,但保持光标位置

  •  14
  • Ben Noland  · 技术社区  · 16 年前

    当我这样做时:

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

    光标移动到文本末尾。

    1 回复  |  直到 16 年前
        1
  •  23
  •   Tim Down    10 年前

    下面是一对函数,用于获取和设置所有主要浏览器中文本区域中的选择/插入符号位置。

    注意:如果您不需要支持IE<=8,只需使用 selectionStart 和 selectionEnd 属性( MDN ). 下面所有复杂的代码都只是为了支持旧版本的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();
        }
    }
    

    更改textarea的值时,请先保存所选内容,然后再还原:

    var t = document.getElementById("textarea");
    var sel = getInputSelection(t);
    t.value = some_new_value;
    setInputSelection(t, sel.start, sel.end);
    
        2
  •  0
  •   Tom Davenport    5 年前

    十年后,这就是我想到的替换文本区域中的项目的方法。当替换为较长或较短的文本时,需要一些额外的处理来调整插入符号或选择。

    // find and replace in textarea while preserving caret and selection
    function replaceText(el, findText, replaceWithText) {
        var text = el.value;
        var selectionStart = 0;
        var selectionEnd = 0;
      // only support modern browsers for preserving caret and selection
        if (el.setSelectionRange) {
            selectionStart = el.selectionStart;
            selectionEnd = el.selectionEnd;
        }
        var start = 0;
        while ((start = text.indexOf(findText, start)) > -1) {
            var end = start + findText.length;
            text = text.substr(0, start) + replaceWithText + text.substr(end);
            if (selectionStart < end) {
                selectionStart = Math.min(selectionStart, start + replaceWithText.length);
            } else {
                selectionStart = selectionStart + replaceWithText.length - (end - start);
            }
            if (selectionEnd < end) {
                selectionEnd = Math.min(selectionEnd, start + replaceWithText.length);
            } else {
                selectionEnd = selectionEnd + replaceWithText.length - (end - start);
            }
            start += replaceWithText.length;
        }
      // don't do anything unless we need to (otherwise destroys undo)
        if (el.value != text) { 
            el.value = text;
            if (el.setSelectionRange) {
                el.selectionStart = selectionStart;
                el.selectionEnd = selectionEnd;
            }
        }
    }
    Place caret on or after the word LONGER, or select some text after or including it:
    <br />
    <textarea id='t'>Here is
    some LONGERtext
    to replace</textarea>
    <br />
    <input type="button" onclick="replaceText(document.getElementById('t'),'LONGER',''); document.getElementById('t').focus();" value="remove word LONGER" />