代码之家  ›  专栏  ›  技术社区  ›  Feelsbadman

ContentEditable环绕元素(按标记);无法将光标从新环绕的选择中移出

  •  0
  • Feelsbadman  · 技术社区  · 7 年前

    我的学校项目网站上有一个DIV,它是一个用户友好的文本编辑器。但是,如果我选择编辑器中的所有文本并尝试用 <code> tags </code> 我无法将光标从中取出,它不断地将我键入的内容添加到同一个标记中,即 <code> .

    过了一段时间我放弃了,但后来我发现 this 回答并尝试修改上面提到的JSfiddle,希望它能够工作。但没有运气。

    如果我,比方说,选择任何一行中的最后一个单词,并用 <代码& GT; 标签,我可以把光标从没有包围的文本中拿出来,但最后没有明文可跳,所以光标卡在里面。 <代码& GT;

    如何确保光标不会卡在添加的标记中? 也许是一种将光标移出的方法?

    jsFiddle

    function surroundSelection() {
        var code = document.createElement("code");
        code.style.fontStyle = "italic";
        code.style.color = "#333";
        code.style.background = "#ddd";
        
        if (window.getSelection) {
            var sel = window.getSelection();
            if (sel.rangeCount) {
                var range = sel.getRangeAt(0).cloneRange();
                range.surroundContents(code);
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    }
    div, input {
      padding:10px; 
      
    }
    
    div {border:1px solid;}
    <input type="button" onclick="surroundSelection()" value="Surround">
    <div contenteditable="true">One two three four</div>
    2 回复  |  直到 7 年前
        1
  •  1
  •   Bibberty    7 年前

    这里有点奇怪。不再使用环绕,而是将内容复制到新节点中。然后在末尾添加一个空格。现在可以在代码块后单击,即使选中了所有文本。

    编辑:添加sel.collapsetoend();根据注释(谢谢)。它通过将用户直接放入正常的输入上下文来提高体验。但是,空间仍然是必需的,没有它就不能工作。

    编辑:现在为开始和结束添加空间。

    编辑:删除发送到服务器的间隔。

    function surroundSelection() {
      let code = document.createElement("code");
      code.style.fontStyle = "italic";
      code.style.color = "#333";
      code.style.background = "#ddd";
      const newSpan = () => {
        let span = document.createElement('span');
        span.classList.add('codespacer');
        span.innerHTML = '&nbsp;';
        return span;
      }
    
      if (window.getSelection) {
        let sel = window.getSelection();
        if (sel.rangeCount) {
          let range = sel.getRangeAt(0).cloneRange();
          code.innerHTML = range.toString();
          range.deleteContents();
          range.insertNode(newSpan());
          range.insertNode(code);
          range.insertNode(newSpan());
          sel.removeAllRanges();
          sel.addRange(range);
          sel.collapseToEnd();
        }
      }
    }
    
    
    function getContentForSave() {
      let codeSection = document.querySelector('#codeSection');
      // Copy into a temporary element (otherwise the text will change in the UI)
      let tempSection = document.createElement('div');
      tempSection.innerHTML = codeSection.innerHTML;
      console.log(`Before: ${tempSection.innerHTML}`);
      
      // Remove all codespacers 
      let spacers = tempSection.querySelectorAll('.codespacer');
      for(let space of spacers) {
        tempSection.removeChild(space);
      }
      console.log(`After: ${tempSection.innerHTML}`);
      
      return tempSection.innerHTML;
    }
    div,
    input {
      padding: 10px;
    }
    
    div {
      border: 1px solid;
    }
    <input type="button" onclick="surroundSelection()" value="Surround">
    <div contenteditable="true" id="codeSection">One two three four</div>
    <input type="button" onclick="getContentForSave();" value="Test For Save">
        2
  •  1
  •   Derek Nguyen    7 年前

    我想你能克服它的一个方法是加上一个空格 textNode 在代码之后,然后将光标移动到其位置。这样,用户可以立即继续写入普通文本。

    以下是故障:

    • 创建包含空格字符的textNode document.createTextNode('\u00A0') . 注释,文字 ' ' 我的浏览器(Chrome70)不工作。
    • 将新的空文本节点添加到 div .
    • 将新的空文本节点添加到当前节点 range 具有 range.setEnd() 所以我们可以使用 selection.collapseToEnd() 方法将光标移动到最末端。

    完全( fiddle )

    + function addPad() {
    +   var $input = document.querySelector('div');
    +   var pad = document.createTextNode('\u00A0');
    +   $input.appendChild(pad);
    +   return pad;
    + }
    
      function surroundSelection() {
        var sel = window.getSelection();
        if (!sel || !sel.rangeCount) return;
    
        var code = document.createElement("code");  
        var range = sel.getRangeAt(0).cloneRange();
        range.surroundContents(code);
        sel.removeAllRanges();
        sel.addRange(range);
    
    +   // create empty node + add it to div
    +   var padNode = addPad();
    
    +   // update the current range to include the empty node.
    +   // since we only add 1 space, the `offset` is set to 1.
    +   range.setEnd(padNode, 1);
    
    +   // move the cursor to very end of range
    +   sel.collapseToEnd();
      }