contentEditable 不会将第一行换行到标签中

问题描述 投票:0回答:8

我有一个设置了 contentEditable 属性的 div。

我遇到的麻烦是我输入的第一行没有被包裹在标签中,但后续行却被包裹起来。

所以输入:

qwerty
zxcv
asdfg

结果:

<div class="editable" contentEditable="true">
    qwerty
    <div>zxcv</div>
    <div>asdfg</div>
</div>

所以我需要

qwerty
线变成
<div>qwerty</div>

html contenteditable
8个回答
8
投票

我在 Chrome 中添加 div 时遇到了问题。仅当您的 div 包含 br 标签时它才有效:

<div class="editable" contentEditable="true">
  <div>
    <br>
  </div>
</div>

@nicholas_r 是对的,删除可编辑div中的最后一个字符也会删除开头添加的div。您可以通过抓住最后一个“退格键”来避免这种情况。使用 jquery 的简单解决方案:

$(".editable").on('keydown', function(event) {
  if (event.keyCode === 8 && $(this).html() == '<div><br></div>') {
    event.preventDefault();
  }
}

4
投票

如果有帮助,运行以下命令将让您包装未包装的 div 。如果您在按键或类似的情况下触发它,即使用户从 div 中删除所有内容,它也会起作用。

 $(".editable").contents().filter(function() {
    return this.nodeType == 3;
 }).wrap('<div></div>');

2
投票

如果您从一个内部包含

div
的元素开始,如下所示:

<div class="editable" contentEditable="true">
    <div></div>
</div>

您输入的第一行最终将被包裹在

div
中。

更新:

这是特定于浏览器的。虽然在问题发布时它确实在大多数浏览器中工作,但它不一定在最新的浏览器版本中工作。最好的判断方法就是测试一下。


2
投票

这些解决方案中的大多数在 2017 年的 Chrome(版本 61.x)中对我来说不起作用,并且 Kasper 的答案对我来说似乎太混乱了。

据我所知,在

""
事件上简单检查
<br>
input
可以处理所有可能的情况,包括退格、删除和复制粘贴:

$("[contenteditable='true']")
  .on("input", function ()
  {
    var $editable = $(this);
    if ($editable.html().trim() === "" || $editable.html().trim() === "<br>")
      $editable.html($("<div><br></div>"));
  })
  .trigger("input");

请注意,我还在初始化时触发

input
事件,以确保初始内容设置正确,但这可能需要也可能不需要,具体取决于您的特定需求。

https://jsfiddle.net/25ujvrn0/


更新:现代化的非 jQuery 替代方案:

document.querySelectorAll("[contenteditable='true']").forEach(editable => {
    editable.addEventListener("input", function () {
        if (editable.innerHTML.trim() === "" || editable.innerHTML.trim() === "<br>") {
            editable.innerHTML = "<div><br></div>";
        }
    });
    editable.dispatchEvent(new Event("input"));
});

1
投票

我做了类似的事情,它非常有效地确保文本的第一行始终有一个 div 包装器。

这样,如果用户单击该字段及其空白(初始状态),它将在其中放置一个空白,以确保他们的光标位于新 div 内。

$editable.on('focus', function() {
  if ($(this).text().trim() === '') {
    console.log('editable is blank, insert a div');
    $(this).append($('<div>&nbsp;</div>'));  
  }
});

您可以在保存数据之前删除前导空格(如果重要)。


1
投票

对于 2017 年或之后遇到过这个问题的人来说,这些答案在 Chrome 中都不适合我,而那些试图提出智能解决方案的人并没有涵盖我的所有案例。

虽然只在Chrome中进行了测试,而且有点粗糙,但这涵盖了3个主要场景:

  1. 用户尝试删除空
    contenteditable
    div 中的内容。
  2. 用户尝试使用
    contenteditable
    ctrl+a Delete
    删除
    ctrl+a Backspace
    div 中的所有内容。
  3. 用户尝试通过将全选
    contenteditable
    替换为自己选择的字母来删除
    ctrl-a
    div 中的所有内容。

一个 JSFiddle 演示。

document.getElementById("editor").addEventListener("keydown", function(e){
  if(e.which == 8 && document.getElementById("editor").innerHTML=="<div><br></div>"){  // 8 is backspace
    e.preventDefault()
  }
  if (window.getSelection && e.which == 8 || e.which == 46 && window.getSelection){ // 8 is backspace, 46 is delete
    let selection = window.getSelection().toString();
    let editorText = document.getElementById("editor").innerText;

    if (editorText == selection){
      document.getElementById("editor").innerHTML="<div><br></div>"
      console.log("prevented a ctrl+a delete")
    }
  else if (window.getSelection){
    let selection = window.getSelection().toString();
    let editorText = document.getElementById("editor").innerText;

    if (editorText == selection){
      document.getElementById("editor").innerHTML="<div>"+e.which+"</div>";
      console.log("safely did a ctrl+a " + e.which)
    }
  }

  e.preventDefault()
  }
})

1
投票

背景
这是 OP 的解决方案,可确保内容可编辑 div 中的第一行始终被换行并修复常见错误,例如:

  • 擦除编辑器并立即键入后解开第一行。
  • 删除编辑器后添加换行符。
  • Kasper Fredenslund 提到的所有问题:
    • Ctrl + A + Del
    • Ctrl + A + 退格键
    • Ctrl + A + 用户输入的任何内容

它使用事件侦听器来捕获用户何时聚焦于编辑器以及何时离开。有关更多上下文,请阅读代码中的注释。

代码
下面是代码的完整工作小提琴。我的原始示例可以在这个 JS Fiddle 页面找到。

// On Dom Ready
document.getElementById('editor').addEventListener('focusin', checkEditor);
document.getElementById('editor').addEventListener('focusout', checkEditor);

function checkEditor() {
  // Get the DOM element that the user is in
  // Allows you to have multiple editos on one page
  // Next 3 lines of code from: https://stackoverflow.com/a/1553668/3193156
  var e = event || window.event;
  var elem = e.target || e.srcElement;
  if (elem.nodeType == 3) {
    elem = elem.parentNode;
  } // Defeat Safari bug
  // Grab the elements inner HTML
  var html = elem.innerHTML
    // If html is empty or does not start with a div see if we need to fix something
  if (html == '' || html.substr(0, 5) != '<div>') {
    notify('Running editor checks.');
    var index;
    // Catch bug where a line break is added after a user uses backspace to wipe the editor
    if (html.substr(0, 4) == '<br>') {
      notify('Removed line break.');
      index = html.indexOf('\n');
      // If there are any lines after this line break save them
      if (index > -1) {
        html = html.substr(html.indexOf('\n') + 1);
      } else {
        html = '';
      }
      elem.innerHTML = html;
      // If everything is ok return otherwise keep processing
      if (html != '' && html.substr(0, 5) == '<div>') {
        return;
      }
    }
    // Catch bug where first line after erasing editor does not get wrapped
    index = html.indexOf('\n');
    if (index > -1) {
      notify('Wrapped the fist line, did not check the rest.');
      html = html = '<div>' + html.substr(0, html.indexOf('\n') + 1) + '</div>' + html.substr(html.indexOf('\n') + 1);
      elem.innerHTML = html;
      return;
    } else {
      html = html.trim();
      if (html.length > 0) {
        notify('Wrapped the fist line');
        html = '<div>' + html.trim() + '</div>';
        elem.innerHTML = html;
        return;
      }
    }
    // If we made it here the editor shold be considered empty, reset it
    notify('Editor reset.');
    var div = document.createElement('DIV');
    div.innerHTML = '<br>';
    elem.appendChild(div);
  }
}

function notify(msg) {
  var div = document.createElement('DIV');
  div.innerHTML = msg;
  document.getElementById('messages').appendChild(div);
}
#editor {
  width: 90%;
  height: 200px;
  padding: 1rem;
  border: 1px solid #000;
}
<div id="editor" contenteditable="true">

</div>
<div id="messages">
</div>

待办事项/缺失
该解决方案回答了OP,但不考虑以下用例:

  • 粘贴内容后查看结果;这需要逐行进行并包装所有内容。
  • 检查第一行之后的任何其他行;不常见,但我相信您最终可能会在内容末尾看到未换行的行,具体取决于浏览器。

0
投票

仅仅简单的

<div></div>
是行不通的。

如果您正在寻找 jQuery 解决方案,这里是代码:

$('.contenteditable').on 'focus', ->
  if $(@).text().trim() == ''
    $(@).append($('<div><br /></div>'))
© www.soinside.com 2019 - 2024. All rights reserved.