在内容可编辑元素上按 Enter 时插入 BR 或 P 标签的跨浏览器方式

Cross-browser way to insert BR or P tag when hitting Enter on a contentEditable element

本文关键字:BR 标签 方式 浏览器 插入 编辑 元素 Enter      更新时间:2023-09-26

当你在contentEditable元素上按Enter键时,每个浏览器都会以不同的方式处理结果代码:Firefox插入BR标签,Chrome插入DIV标签,而Internet Explorer插入P标签。

我拼命寻找一种解决方案,至少为所有浏览器使用 BR 或 P,最常见的答案是:

插入 BR 标签 :

$("#editableElement").on("keypress", function(e){
      if (e.which == 13) {
        if (window.getSelection) {
          var selection = window.getSelection(),
              range = selection.getRangeAt(0),
              br = document.createElement("br");
          range.deleteContents();
          range.insertNode(br);
          range.setStartAfter(br);
          range.setEndAfter(br);
          selection.removeAllRanges();
          selection.addRange(range);
          return false;
        }
      }
    });

但这不起作用,因为浏览器似乎不知道如何在<br>后设置插入符号,这意味着以下内容没有任何用处(特别是如果您在将插入符号放置在文本末尾时按 Enter 键):

range.setStartAfter(br);
range.setEndAfter(br);

有些人会说:使用双<br><br>但当您在文本节点内按 Enter 时,这会导致两个换行符。

其他人会说总是在 contentEditable 的末尾添加一个额外的<br>,但是如果您有<div contenteditable><p>text here</p></div>并且将光标放在文本末尾然后按 Enter 键,您将获得错误的行为。

所以我对自己说,也许我们可以用P代替BR,常见的答案是:

插入 P 标签:

document.execCommand('formatBlock', false, 'p');

但这也不能始终如一地工作。

如您所见,所有这些解决方案都有待改进。有没有其他解决方案可以解决这个问题?

一种可能的解决方案:在 <br> 元素后附加一个具有零宽度空格字符的文本节点。这是一个非打印零宽度字符,专门设计用于:

。使用脚本时指示文本处理系统的单词边界 不使用显式间距或字符后(例如 斜杠),后面不跟可见空格,但之后有 可能不过是换行符。

(维基百科)

在Chrome 48,Firefox 43和IE11中测试。

$("#editableElement").on("keypress", function(e) {
  //if the last character is a zero-width space, remove it
  var contentEditableHTML = $("#editableElement").html();
  var lastCharCode = contentEditableHTML.charCodeAt(contentEditableHTML.length - 1);
  if (lastCharCode == 8203) {
    $("#editableElement").html(contentEditableHTML.slice(0, -1));
  }
  // handle "Enter" keypress
  if (e.which == 13) {
    if (window.getSelection) {
      var selection = window.getSelection();
      var range = selection.getRangeAt(0);
      var br = document.createElement("br");
      var zwsp = document.createTextNode("'u200B");
      var textNodeParent = document.getSelection().anchorNode.parentNode;
      var inSpan = textNodeParent.nodeName == "SPAN";
      var span = document.createElement("span");
      
      // if the carat is inside a <span>, move it out of the <span> tag
      if (inSpan) {
        range.setStartAfter(textNodeParent);
        range.setEndAfter(textNodeParent);
      }
      // insert the <br>
      range.deleteContents();
      range.insertNode(br);
      range.setStartAfter(br);
      range.setEndAfter(br);
      
      // create a new span on the next line
      if (inSpan) {
        range.insertNode(span);
        range.setStart(span, 0);
        range.setEnd(span, 0);
      }
      // add a zero-width character
      range.insertNode(zwsp);
      range.setStartBefore(zwsp);
      range.setEndBefore(zwsp);
      
      // insert the new range
      selection.removeAllRanges();
      selection.addRange(range);
      return false;
    }
  }
});
#editableElement {
  height: 150px;
  width: 500px;
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable=true id="editableElement">
  <span>sample text</span>
</div>

您可以在此处查看完整的跨浏览器实现。有很多黑客可以使其工作。链接中的此代码将帮助您设备解决方案。

Geko和IE黑客的例子:

doc.createElement( 'br' ).insertAfter( startBlock );
// A text node is required by Gecko only to make the cursor blink.
if ( CKEDITOR.env.gecko )
    doc.createText( '' ).insertAfter( startBlock );
// IE has different behaviors regarding position.
range.setStartAt( startBlock.getNext(), 
    CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START :
        CKEDITOR.POSITION_AFTER_START );