阻止contentedable模式创建<span>标记</span>

时间:2013-10-08 09:05:47

标签: css html5 google-chrome contenteditable html

当我在div上使用浏览器contenteditable = true以便让用户更新其中的文本时,我遇到了这个问题(使用Chrome):

当使用 delete 退格键删除换行符(跳回一行)时,浏览器会在该文本周围插入一个带内联样式集的标记。

这实在令人沮丧,因为它不仅会这样做,还会为该span标记添加内联样式,例如,如果我的字体颜色当前为黑色,则会为该span标记添加style =“color:black” 。

结果是我无法再用我的工具栏编辑该文本的颜色,因为它已通过内联样式很难设置为span标记。如果我使用删除键备份一行,也会发生同样的事情。

任何人都可以教我一两件关于满足的内容,或建议一种方法来删除跨度:s,如果它不可能阻止这种浏览器行为..

**要重现此问题** - 在浏览器中创建一个div,在其上设置内联样式,例如font-size:36px - 使用浏览器中可编辑的内容编辑div的文本,使用手动换行符写几行。 - 现在将光标放在FRONT OF / FRFORE的一段文本中并点击退格键。现在应该在光标前面的文本周围生成一个span标记,并改变它的样式。

更新 * * 所以我尝试了几种不同的解决方案,但收效甚微。首先我尝试删除所有标签,但之后我也丢失了所有的换行符(也许更好的正则表达式可以解决这个问题,我不是regExp写的专家)。

下面的所有函数首先调用keyup事件,但后来我将它们附加到取消选择文本框。如何解雇以下功能与问题无关。

        //option to remove all tags
        var withTags = $(textObject).html();
        var withoutTags = withTags.replace(/<(?:.|\n)*?>/gm, '');       
        $(textObject).html(withoutTags);

我的第二次尝试更成功,删除了文本框下面的对象的样式标记(文本框内的divs跨越了chrome添加),这是我的第一个代码

        //option to remove style of elements
        $(textObject).children().each(function() {
            $(this).removeAttr('style');
            console.log('removing style from first level element: '+this);

        });

然后我意识到每次编辑文本框时,chrome都可能会添加上面代码无法达到的新嵌套div / span标记级别,所以我这样做了:

        //option to remove style of elements
        $(textObject).children().each(function() {
            $(this).removeAttr('style');
            console.log('removing style from first level element: '+this);

            //And of course it would be all too easy if chrome added only one level of elements...
            $(this).children().each(function() {
                $(this).removeAttr('style');
                console.log('removing style from second level element: '+this);
            });

        });

但这还不够,因为嵌套的数量理论上可以是无限的。仍在努力寻找更好的解决方案。感谢任何输入=)

5 个答案:

答案 0 :(得分:6)

实际上,问题是它不仅会插入span和p,而且如果您碰巧复制,它会插入整个表格那里有tbody和rows 。 所以,我发现为我工作的唯一选择是:

$(document).on("DOMNodeInserted", $.proxy(function (e) {
        if (e.target.parentNode.getAttribute("contenteditable") === "true") {
            with (e.target.parentNode) {
                replaceChild(e.target.firstChild, e.target);
                normalize();
            }
        }
}, this));

是的,它在一定程度上影响了整个页面的性能,但它会阻止将表格和内容插入到满足的页面中。

<强>更新
当您希望的内容包含在一个span / p标记级别时,上面的脚本只处理基本情况。但是,如果从Word复制,则最终可能会复制整个表格。 所以,这是代码,它处理我迄今为止所抛出的所有内容:

$(document).on("DOMNodeInserted", $.proxy(function (e) {
    if (e.target.parentNode.getAttribute("contenteditable") === "true") {
        var newTextNode = document.createTextNode("");
        function antiChrome(node) {
            if (node.nodeType == 3) {
                newTextNode.nodeValue += node.nodeValue.replace(/(\r\n|\n|\r)/gm, "")
            }
            else if (node.nodeType == 1 && node.childNodes) {
                    for (var i = 0; i < node.childNodes.length; ++i) {
                        antiChrome(node.childNodes[i]);
                    }
            }
        }
        antiChrome(e.target);

        e.target.parentNode.replaceChild(newTextNode, e.target);
    }
}, this));

此外,您可以随意修改中间的正则表达式,以便删除在您的情况下特别危险的符号。

更新2
经过一段时间的思考和谷歌搜索,我只是将上面的代码包装成简单的jQuery插件,以简化使用。这是GitHub link

答案 1 :(得分:2)

目前,我正在使用

        $(textObject).find('*').removeAttr('style');

取消选择可编辑区域。

也可以在keyup上使用。

答案 2 :(得分:2)

以下是我解决这个问题的方法

jquery remove <span> tags while preserving their contents (and replace <divs> and <p>:s with <br>)

我保留所有div,span和p标签的文本,删除这些标签,并用br替换所有div和p。我是在模糊的情况下做的,最好是在每次keydown上都这样做,但是因为我必须遍历所有这些%#¤¤%&amp; (你说的)嵌套元素。

答案 3 :(得分:1)

添加样式显示:inline-block;为了contenteditable,它不会在chrome中自动生成div,p,span

答案 4 :(得分:0)

伙计,这个问题的时机很疯狂。我正在做的事情就是强迫所有内容都在段落标签内,这是可信的div。

因此,我处理这个废话的方式是通过在每次击键时展平每个<p>

由于.text()选择元素的所有文本,包括其子元素,我可以设置(在coffeescript中)

t = $(element).text()
$(element).children().remove()
$(element).text(t)

这解决了我的问题。顺便说一句,这些浏览器实现者确实非常糟糕。这里有一个很大的机会让这很容易,因为它确实是网络的未来。