防止Chrome使用<span> </span> </p>包装已加入<p>的内容

时间:2013-02-22 00:47:42

标签: javascript html5 google-chrome contenteditable

我发现Chrome中的一个不良行为是通过删除它们之间的分隔加入两个<p>时发生的。虽然<p>标记已正确加入,但Chrome会将最右侧<p>标记的内容包含在<span>中。

修改:所有块元素都会发生这种情况,而不仅仅是p个标记。

示例

例如,当从以下块中删除分隔</p><p>时:

<div contenteditable="true"><p>p one.</p><p>p two.</p></div>

变成:

<div contenteditable="true"><p>p one.<span style="font-size: 16px; line-height: 1.44;">p two.</span></p>

小提琴中的例子:Chrome wrapping contents of joined <p> with a <span>

问题

有没有一种简单的方法来防止铬这样做?它导致了我非常想要摆脱的可怕标记。

8 个答案:

答案 0 :(得分:10)

有一种方法,但你需要主动设置几种风格。我们的想法是告诉Chrome已经注意了样式,因此不需要添加SPAN来满足样式要求。 基本上,您需要将chrome添加的样式添加到您的contenteditable div下的span类中(参见下面的示例)。

Edited fiddle

对于你的例子:

  • 我添加了一个&#34;编辑&#34;类似于满足的DIV
  • 我在样式
  • 中添加了.edit p, span

这变为:

.edit {
  border: 1px solid gray;
  padding: 10px;
}
.edit p, span {
  line-height: 1.44; font-size: 16px;
}

DIV:

<div contenteditable="true" class="edit">...</div>

请注意,您通常不需要font-size: 16px;。我需要添加这个,因为小提琴在contenteditable中定义了一些字体大小。在一个独立的页面上,我并不需要它。

您需要应用此Chrome&#39;补丁&#39;发生的任何元素(如果你需要UL,OL ......然后按照上面的示例逻辑添加所需的内容)

答案 1 :(得分:4)

我知道解决它并不是一个真正的答案,而是暗示如何解决它(但是很长时间来回答Petah问题我将如何解决它)

一般情况下,您会检查何时可能发生此类错误。对于span创建的情况,您将监听所有keydownkeypress事件,并检查密钥是退格/删除密钥,还是插入字符的每个密钥(如果是真正的选择。

如果是这种情况,那么您需要检查当前选择(插入标记的位置或实际选择),然后您知道下一个文本元素或节点是哪个。然后,如果在插入标记后直接创建了keypress,则需要检查下一个keyupspan。根据浏览器错误,您需要进一步检查。如果有一个创建再次打开其内容。可以使用附加Mutation事件和帮助属性。

但是我需要说我自己放弃了这个并转而使用ckeditor 4.我不需要的大多数功能都是一个非常大的库。但是由于大量此类错误的原因,我没有看到另一种解决方案。

修改 这里是js小提琴的更新,显示了Mutable事件的想法: http://jsfiddle.net/THPmr/6/

但这不是防弹,只是为了展示它是如何实现的(仅在chrome 27.0.1422.0中测试,如果第二个p中包含多于一个文本元素,则可能无效)

答案 2 :(得分:3)

这是我删除额外跨度的看法

document.querySelector('[contenteditable=true]')
  .addEventListener('DOMNodeInserted', function(event) {
    if (event.target.tagName == 'SPAN') {
      event.target.outerHTML = event.target.innerHTML;
    }
  });

答案 3 :(得分:2)

CSS正在影响标记在可信范围内的制作方式:

div,pre {     边框:1px实心灰色;     填充:10px;     line-height:1.44; }

删除行高线,不再出现问题。

通常会出现几个与默认样式相关的错误信息:How to avoid WebKit contentEditable copy-paste resulting in unwanted CSS?

编辑 JsFiddle IS间接影响了这一点(tinkerbin表现不同),因为它的'CSS(normalize.css)。试试这个:

  1. 跑你的小提琴
  2. 检查<p>
  3. 禁用CSS堆栈中的所有font-size声明 - 包括您的line-height
  4. 执行退格
  5. 没有内嵌范围
  6. 解决方案1 ​​:使用类和ID。

    不要为pdiv声明字体大小,而是为p.main-content或更简单地.main-content声明字体大小。 如果您的元素内容的字体大小来自浏览器的内部默认CSS,那么Chrome将不会添加额外的标记/内联样式。

    解决方案2 :使用消毒剂。

    我个人会选择#1,因为在这样的通用标签中指定字体大小和拼写错误绝不是一个好习惯。

答案 4 :(得分:2)

到目前为止,我发现的最好的方法是监听DOMNodeInserted并检查tagName。如果是跨度,则可以删除标记但保留内容。这也将光标保持在正确的位置。

function unwrap(el, target) {
    if ( !target ) {
        target = el.parentNode;
    }
    while (el.firstChild) {
        target.appendChild(el.firstChild);
    }
    el.parentNode.removeChild(el);
}

var AutoFix = true;

document.getElementById('editable')
.addEventListener('DOMNodeInserted', function(ev) {
    if ( !AutoFix ) {
        return;
    }
    if ( ev.target.tagName=='SPAN' ) {
        unwrap(ev.target);
    }
});

我添加了一个布尔型'AutoFix',因此您可以在需要插入跨度时禁用自动dom更改,因为此事件会在任何dom更改时触发。例如。如果您有一个工具栏,允许用户插入类似&lt; span class =“highlight”&gt; ...&lt; / span&gt;。

就我所见,代码在IE或FireFox中没有任何副作用。

答案 5 :(得分:1)

这也激怒了我,但我找到了一个现在运作良好的解决方案。

$('#container span').filter(function() {
    $(this).removeAttr("style");
    return $(this).html().trim().length == 0;
}).remove();

我只是从span元素中删除样式标记,如果它是空的,则将其删除。您可以根据属性样式进行过滤,但由于我已经在进行循环检查以删除空跨度,我认为最好同时执行这两种操作。

当chrome首次尝试插入为跨度继承的样式时,它确实会创建一个微秒的闪烁,但您只能在删除后立即看到它。

它并不完美,但它快速而简洁。

答案 6 :(得分:0)

从某人博客上发布的评论中找到此链接:

(修正了最新的WebKit版本会生成span元素的错误...) https://github.com/tinymce/tinymce/commit/8e6422aefa9b6cc526a218559eaf036f1d2868cf

答案 7 :(得分:0)

请在此处查看答案:https://stackoverflow.com/a/24494280/2615633 要解决此问题,您可以使用此插件:jquery.chromeinsertfix