【问题标题】:contentEditable does not wrap first line in tagscontentEditable 不会在标签中换行第一行
【发布时间】:2012-09-17 12:28:23
【问题描述】:

我有一个属性为 contentEditable 的 div。

我遇到的问题是我输入的第一行没有被标签包裹,但后面的行会。

所以打字:

qwerty
zxcv
asdfg

结果:

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

所以我需要将qwerty 行变成&lt;div&gt;qwerty&lt;/div&gt;

【问题讨论】:

  • 这在 Chrome 38 中仍然是一个问题。并不是我以任何方式抨击 IE,而是它在 IE 7 中明智地插入了 P 标签。我无法理解 Chrome 怎么可能没有还没有掌握这个基本的多线功能

标签: html contenteditable


【解决方案1】:

我在 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();
  }
}

【讨论】:

  • 一点小提示,$(this).html() 应该是$(this).html().trim() 否则不起作用
  • 不幸的是,突出显示和删除确实会删除它。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    如果您从一个包含div 的元素开始,如下所示:

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

    您键入的第一行最终将被包裹在 div 中。

    更新:

    这是特定于浏览器的。虽然在发布问题时它在大多数浏览器中都可以使用,但在最新的浏览器版本中不一定可以使用。最好的判断方法是测试它。

    【讨论】:

    • 我已经这样做了,它确实有效。不一定是我希望的理想解决方案,但它确实有效。谢谢
    • 只有在你从 div 中删除所有内容时才有效。之后它将在第一行包含&lt;br&gt;,然后第一行将再次展开。
    • 这仅适用于您的 div 包含
      标签 &lt;div&gt;&lt;br&gt;&lt;/div&gt;
    【解决方案4】:

    我做了这样的事情,它非常适合确保在第一行文本上总是有一个 div 包装器。

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

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

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

    【讨论】:

      【解决方案5】:

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

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

      1. 用户尝试删除空 contenteditable div 中的内容。
      2. 用户尝试使用ctrl+a Deletectrl+a Backspace 删除contenteditable div 中的所有内容。
      3. 用户尝试删除contenteditable div 中的所有内容,方法是将完整选择ctrl-a 替换为他们选择的字母。

      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()
        }
      })
      

      【讨论】:

      • 在下面试试我的答案。我认为它可以处理您的所有问题,而无需阻止任何默认的用户/浏览器行为。快速跳转回答:stackoverflow.com/a/47685420/3193156
      【解决方案6】:

      这些解决方案中的大多数在 2017 年的 Chrome(版本 61.x)中都不适用于我,Kasper's answer 对我来说似乎太乱了。

      据我所知,对input 事件的""&lt;br&gt; 的简单检查可以处理所有可能的情况,包括退格、删除和复制粘贴:

      $("[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/

      【讨论】:

      • 这是的答案。这是适用于所有情况的最简单的答案。我希望我能投票两次。
      • @JG.cods 你指的是&lt;input placeholder="" /&gt; 属性吗? developer.mozilla.org/en-US/docs/Web/HTML/Element/… 该属性仅适用于 inputtextarea 元素。如果您希望 placeholder 处理 div 和其他非输入元素,则必须编写自己的自定义代码来处理它,包括如何处理我在上面的回答中概述的“输入为空”检查。在不知道您的自定义占位符代码如何工作的情况下,我无法在我的解决方案中处理占位符。
      • 我属于占位符而不是输入标签:)。是的 contenteditable 有它,但不会马上工作。您必须将样式与占位符和 contenteditable 一起使用,您可以查看此 stackoverflow 问题和答案。 stackoverflow.com/questions/20726174/…
      • @JG.cods 所以就像我说的那样,您的链接提供了一个定制的 hack 以使 placeholder 工作。它通过在 contenteditable div 为空时定义 CSS 伪元素来实现这一点。不幸的是,这个 hack 与这个问题的目标和我在这里的解决方案直接不一致:我们正在努力确保 contenteditable div 从不为空并且始终至少有 &lt;div&gt;&lt;br&gt;&lt;/div&gt; 作为它的内容。要使用此解决方案进行类似的破解,您必须将 CSS :empty 规则替换为 JS 检查空状态并定义一个空类:jsfiddle.net/d1ocypr4
      【解决方案7】:

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

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

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

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

      // 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,不考虑以下用例:

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

      【讨论】:

      • 工作,但是,如果你有占位符,它不能正确显示
      【解决方案8】:

      简单的&lt;div&gt;&lt;/div&gt; 是行不通的。

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

      $('.contenteditable').on 'focus', ->
        if $(@).text().trim() == ''
          $(@).append($('<div><br /></div>'))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-08
        • 1970-01-01
        • 2014-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多