【问题标题】:How to keep the position of the caret in contenteditable element如何保持插入符号在 contenteditable 元素中的位置
【发布时间】:2019-12-29 17:01:43
【问题描述】:

如何在 contenteditable 元素中保持插入符号的位置,当我尝试更新可编辑元素的 innerHTML 时插入符号的位置会跳到行首,我需要一个可以保持插入位置的函数当可编辑元素 innerHTML 更新或更改时插入插入符号,谢谢。

我的代码:

// content editable element
let editor = document.getElementById("editor");

editor.onkeypress = (e) => {
    if (e.keyCode === 32) {
        let lines = editor.children;
        for (let line of lines) {
            line.innerHTML += "Hello World !!!";
        }
    }
}

【问题讨论】:

    标签: javascript html css ecmascript-6


    【解决方案1】:

    我的回答:

    // content editable element
    let editor = document.getElementById("editor");
    
    // on keypress
    editor.onkeypress = () => {
        // get the position of caret
        let pos = getCaretPos(editor.children[0]);
    
        // update the innerHTML
        editor.children[0].innerHTML += "Hello World !!!";
    
        // set the caret position
        setCaretPos(editor.children[0], pos);
    }
    
    function getCaretPos(element) {
        var ie = (typeof document.selection != "undefined" && document.selection.type != "Control") && true;
        var w3 = (typeof window.getSelection != "undefined") && true;
        var caretOffset = 0;
        if (w3) {
            var range = window.getSelection().getRangeAt(0);
            var preCaretRange = range.cloneRange();
            preCaretRange.selectNodeContents(element);
            preCaretRange.setEnd(range.endContainer, range.endOffset);
            caretOffset = preCaretRange.toString().length;
        } else if (ie) {
            var textRange = document.selection.createRange();
            var preCaretTextRange = document.body.createTextRange();
            preCaretTextRange.moveToElementText(element);
            preCaretTextRange.setEndPoint("EndToEnd", textRange);
            caretOffset = preCaretTextRange.text.length;
        }
        return caretOffset;
    }
    
    function setCaretPos(element, position) {
        var node = element;
        node.focus();
        var textNode = node.firstChild;
        var caret = position; // insert caret after the 10th character say
        var range = document.createRange();
        range.setStart(textNode, caret);
        range.setEnd(textNode, caret);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
    

    【讨论】:

      【解决方案2】:

      最简单的答案是不使用innerHTML。如果您使用的是 contenteditable,那么它的全部意义在于您有一个一致的活动 DOM 文档可以处理。如果你插入一个字符串,浏览器就无法知道光标应该在哪里,因为你正在破坏它拥有的所有信息。这很像你做的line.innerHTML = ""; line.innerHTML = "Hello World !!!";,所以光标一直被推到开头/结尾。

      鉴于此,您可以这样做

      if (e.keyCode === 32) {
          // 1. Get the children as a normal JS array, so that adding
          //    children in the next bit of code doesn't break for for-of.
          let lines = Array.from(editor.children);
          // Old Browsers:
          //   let lines = Array.prototype.slice.call(editor.children);
      
          for (let line of lines) {
              const newText = "Hello World !!!";
      
              // 2. Insert the text immediately after the 'line' DOM node.
              line.after(newText); 
              // Older Browsers:
              //   line.parentNode.insertBefore(
              //     document.createTextNode(newText), line.nextSibling);
      
          }
          // 3. Normalize the document, so that if the code above inserted multiple text nodes
          //    in a row (potentially meaning that `editor.children` is no longer just lines), 
          //    the nodes will be merged back together.
          editor.normalize();
      }
      

      在不知道 editor.children 实际具体包含什么的情况下,我不能 100% 确定这会奏效,但类似的东西肯定会。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-17
        • 2019-09-16
        • 2010-11-14
        • 2015-05-31
        • 1970-01-01
        • 2011-08-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多