22

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

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

这真的很令人沮丧,因为它不仅这样做,它还为该跨度标签添加了一个内联样式,例如,如果我的字体颜色当前是黑色,它会向该跨度标签添加一个 style="color:black"。

结果是我不能再用我的工具栏编辑该文本的颜色,因为它已被内联样式硬设置为 span 标签。如果我用删除键备份一行,字体大小也会发生同样的事情。

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

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

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

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

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

我的第二次尝试更成功,通过删除文本框下方对象的样式标签(divs ans 跨越 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);
            });

        });

但这还不够,因为理论上嵌套的数量可能是无限的。仍在研究更好的解决方案。任何输入表示赞赏=)

4

5 回答 5

6

实际上,问题在于,它不仅会插入 span 和 p,而且如果您碰巧复制了一个,它会在其中插入带有 tbody 和行的整个表。因此,我发现为我工作的唯一选择是:

$(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));

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

更新:
上面的脚本只处理基本情况,当你想要的内容被包裹在一层 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链接

于 2014-06-30T15:59:26.793 回答
2

目前,我正在使用

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

在取消选择可编辑区域时。

它也可以在keyup时使用。

于 2013-10-09T09:35:15.823 回答
2

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

jquery 删除 <span> 标签,同时保留其内容(并将 <divs> 和 <p>:s 替换为 <br>)

我保留所有 div、span 和 p 标签的文本,删除这些标签,并用 br 替换所有 div 和 p。我在模糊时执行此操作,最佳方法是在每次按键时执行此操作,但这会消耗太多 CPU,因为我必须遍历所有这些%#¤¤% &(您说过)嵌套元素。

于 2013-10-25T18:19:33.473 回答
1

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

于 2014-07-11T02:56:47.617 回答
0

伙计,这个问题的时机太疯狂了。我对 contenteditable 所做的是强制所有内容都在 contenteditable div 的段落标签内。

因此,我处理创建的这种胡说八道跨度的方式是<p>在每次击键时都将其展平。

由于.text()选择了一个元素的所有文本,包括它的子元素,我可以设置(在咖啡脚本中)

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

这解决了我的问题。顺便说一句,这些浏览器实现者确实把 contenteditable 搞砸了。这里有很大的机会让这一切变得简单,因为它确实是网络的未来。

于 2013-10-10T15:57:19.017 回答