【问题标题】:Force IE contentEditable element to create line breaks on Enter key, without breaking Undo强制 IE contentEditable 元素在 Enter 键上创建换行符,而不破坏 Undo
【发布时间】:2011-01-14 07:46:37
【问题描述】:

在 Internet Explorer 上,contentEditable DIV 会在您每次按 Enter 时创建一个新段落 (<p></p>),而 Firefox 会创建一个<br/> 标签。

正如 here 所讨论的,可以使用 JavaScript 拦截 Enter 键并使用 range.pasteHTML 创建一个 <br/>。但是这样做会破坏撤消菜单;一旦按 Enter 键,您就无法再撤消超过该点。

如何强制 contentEditable 元素在 Enter 上创建单个换行符而不破坏 Undo?

【问题讨论】:

  • 好点 - 甚至可用的所见即所得编辑器也可以帮助解决这个问题,因为他们实现了自己的撤消系统。

标签: html undo contenteditable


【解决方案1】:

不是一个确切的解决方案,而是另一种解决方法。如果您使用标记:

<div contenteditable="true">
<div>
content
</div>
<div>

然后按 enter 将创建新的 div 标签而不是 p 标签。

【讨论】:

  • 有趣!我在其他地方读到过,但由于某种原因,我以前无法使用该技术。刚刚在一个简单的 HTML 页面中尝试过,它在 IE6 IE8 FF36 GC4 中运行良好。但是,如果用户设法删除内部 DIV,它会恢复为 &lt;p&gt; 中断。
  • 是的,我不知道如何避免这种情况。最初contenteditable 是 Microsoft 的专有属性,他们以任何他们想要的方式实现,其中一些是有道理的,但大多数都有太多错误。 FF 实现的错误较少,但做了一些非标准的事情(输入确实应该创建新段落)。这里希望 IE9 重新考虑这个功能。要在它们之间实现任何表面上的一致性,您确实必须考虑使用 javascript。
  • euw!检查剃须刀答案!
  • 我还发现,如果你在内部 DIV 中添加一个类,那么 IE 会将相同的类添加到创建的 DIV 中。这可能是有选择地替换或过滤这些标签的有用技巧。无论如何,这是一个很好的简单解决方案,它对我有用。
  • 我无法确认这适用于 p 标签(它从未创建过 p 标签,而是 div),但将内容包装在额外的外部标签中的解决方案似乎是避免换行符的好方法创建您无法控制的布局破坏元素。
【解决方案2】:

按回车键时按住 shift 键进行中断,不要按住它来读取整个段落。这种行为在 Firefox 中默认情况下是相同的,给定一个包含段落的 contenteditable 区域:即

<div contenteditable="true">
    <p>If you are typing here</p>
<div>

【讨论】:

  • 这是一个很好的观点,但我不能指望我的用户记得始终如一地这样做。
  • 如果人们使用 Word Perfect、Open Office 甚至 Microsoft Word,他们可能会知道惯例,因为它们的行为都相同。伴随编辑的注释就足够了。促进惯例而不是试图打破它。
  • 我完全同意 :) 这是我的用户一旦学会就很少忘记的技巧。它与 Ctrl-Click 在电子表格中选择单个行的空间相同。
【解决方案3】:

假设您要将可编辑的内容发布回服务器。因此,您不应该真正关心用户编辑时是否有段落或中断标记,因为您可以在提交之前(或在服务器上,如果您愿意)解析 HTML 并用中断替换段落实例。这可以让 UNDO 队列为用户运行,但可以让您的 HTML 尽可能干净。

我将进一步假设您将确切知道哪些 DIV 元素将是 contentEditable。在提交表单之前,您可以通过这样的函数运行每个 contentEditable div:

function cleanContentEditableDiv(div) {
  var htmlString = div.innerHTML;
  htmlString     = htmlString.replace(/<\/p>/gim,"<br/>");
  htmlString     = htmlString.replace(/<p>/gim,"");
  return htmlString;
}

然后你在一个循环中调用它(它遍历所有 contentEditable DIV,使用我称之为 ceDivs 的数组),像这样:

ceDivs[i].contentEditable = false; // to make sure IE doesn't try to coerce the contents again

然后:

ceDivs[i].innerHTML = cleanContentEditableDiv(ceDivs[i]);

对此的改进(特别是如果您不想在提交时正确执行此操作),可能是在您喜欢的任何其他时间(onblur 等)清理每个此类 div 的内容并分配每个ceDiv 到它自己的不可见表单元素以供以后提交。与您自己的上述 CSS 建议结合使用,这可能对您有用。它不会保留您对字母的字面要求(即,它不会让 Javascript 使 IE 的行为与在幕后编码的行为不同),但出于所有实际目的,效果是相同的。用户得到他们想要的,你得到你想要的。

当您使用它时,您可能还想清除 IE 中的空格字符串。如果用户键入多个空格(有些人仍然在句点后这样做),IE 插入的不是 [space][space] 而是 [space] ,一个初始空格字符 (String.fromCharCode(32)) 加上尽可能多的空格 空间中剩余的实体。

【讨论】:

  • 我正在开发客户端编辑器。在可编辑元素中复制和粘贴非常重要,因此是否保留换行符确实
  • Robusto 在清理 html 方面提出了一个非常好的观点。 Contenteditable 会产生一些你见过的最糟糕的 html。无论如何,在服务器端清理 html 是一个好主意。就使用 html 进行客户端标记而言,这是一个好主意。从长远来看,我们放弃了支持希望从 word 中复制粘贴的客户:$
  • 我同意清理 HTML 是个好主意,但是一旦我清理了 HTML,您就不能再使用撤消菜单来撤消更改!这就是我问题的重点。
  • 丹,两点:1. 在我建议的方案中,您的换行符被保留。他们只是在事后重新调整。 2. 如果您在表单提交之前离开清理,则您将整个 UNDO 队列留给用户。不应该期望在表单提交之后保存该文件。
  • Robusto,我试图在用户按下 Enter 键的那一刻生成单行距,而不会在每次用户按下 Enter 时都中断 Undo。清理服务器端是一种很好的做法,但与我的问题无关。
【解决方案4】:

使用&lt;BR&gt;而不是&lt;P&gt;(在IE9中测试。在&lt;BR&gt;(pasteHTML("&lt;br&gt;&amp;nbsp;"))之后的旧版本中可能需要nbsp;

在 keydown 事件中使用它:

if (e.keyCode == 13) {
 var range = document.selection.createRange();
 range.pasteHTML("<br> ");
 range.moveStart("character", 0);
 range.moveEnd("character", -1);
 range.select();
 return false;
}

【讨论】:

  • 这是仅限 IE 的解决方案吗?其他浏览器呢?
  • 记住 - 一个 13 键可以是一个列表项插入
【解决方案5】:

可能无法做到这一点。但是,可以通过使用 CSS 移除段落标签周围的内置边距,使 &lt;p&gt; 标签 看起来 像单行中断:

p { margin: 0; }

这种方法有一个缺点:如果用户需要在 contentEditable 元素中复制/粘贴文本,文本可能会在元素内显示为单行距,但在元素外是双行距。

更糟糕的是,至少在某些情况下,IE 会在粘贴过程中自动检测双换行符,将它们替换为&lt;p&gt; 标签;这会弄乱粘贴文本的格式。

【讨论】:

  • 抛开元数据:我通常不愿意发布我自己的赏金的答案,但已经四天没有回复了;我不想看到这些点消失在以太中......
  • 最佳解决方案 IMO。由于 IE11 不再在用户代理中发送“msie”,我们必须为它编写一个全新的案例,使用一系列全新的 hack ......该死 - 让我们做一些边缘的事情。
【解决方案6】:

IE 将文本节点与 Enter 键按下时的&lt;p&gt; 标记绑定。实现换行Shift+Enter。 Firefox 在 Enter 按键上添加了一个&lt;br&gt; 标签。要使两种浏览器的行为通用,您可以执行以下操作:

假设以下标记:

<div id="editableDiv" contentEditable="true"></div>

Javascript [假设下面的代码在一个函数闭包中,这样你就不会用全局变量来膨胀页面]:

 (function () {
     //Initialize _shiftKeyPressed to false
     var _shiftKeyPressed = false;
     $('#editableDiv').live('keydown', function (e) {
         if (e.keyCode == 16) {
             // SHIFT key is pressed
             _shiftKeyPressed = true;
         }
     }).live('keyup', function (e) {
         if (e.keyCode == 16) {
             // SHIFT key is release
             _shiftKeyPressed = false;
         }
     }).live('keypress', function (e) {
         if (e.keyCode == 13 && !_shiftKeyPressed && !jQuery.browser.msie) {
             // Insert a PARAGRAPH in Firefox instead of a BR
             // Ignores SHIFT + ENTER
             document.execCommand("insertParagraph", false, true);
         }
     })
 })();

注意:此脚本在 jQuery $.browser

【讨论】:

    【解决方案7】:

    在使用 Internet Explorer 时考虑使用&lt;span contenteditable="true"&gt;&lt;/span&gt;。您可能不想在 Chrome 上执行此操作,因为焦点看起来很有趣。您可能希望实现自己的 onfocusonblur 代码。

    【讨论】:

      猜你喜欢
      • 2011-01-04
      • 2011-12-31
      • 2014-07-21
      • 2012-10-01
      • 2016-08-20
      • 1970-01-01
      • 1970-01-01
      • 2019-03-19
      • 2011-03-06
      相关资源
      最近更新 更多