首先,请注意,通过粘贴从 Word(或任何其他 HTML 源)收到的 HTML 将因源而异。即使是不同版本的 Word 也会给你完全不同的输入。如果您设计的一些代码可以完美地处理您拥有的 MS Word 版本的内容,那么它可能根本不适用于不同版本的 MS Word。
此外,一些来源会粘贴看起来像 HTML 但实际上是垃圾的内容。当您将 HTML 内容粘贴到浏览器的富文本区域时,您的浏览器与该 HTML 的生成方式无关。不要指望它在你的任何想象中都是有效的。此外,当 HTML 插入富文本区域的 DOM 时,您的浏览器会进一步处理 HTML。
因为潜在的输入变化很大,并且因为可接受的输出很难定义,所以很难为这类事情设计一个合适的过滤器。此外,您无法控制未来版本的 MS Word 将如何处理其 HTML 内容,因此您的代码将难以适应未来。
然而,振作起来!如果世界上所有的问题都是简单的问题,那将是一个非常无聊的地方。有一些潜在的解决方案。可以保留 HTML 的好的部分并丢弃不好的部分。
看起来您的基于 HTML 的 RTE 与大多数 HTML 编辑器一样工作。具体来说,它有一个 iframe,并且在 iframe 内的文档上,它已设置designMode
为“on”。
paste
当事件发生在<body>
该 iframe 内的文档元素中时,您需要捕获该事件。我在这里非常具体,因为我必须:不要将它困在 iframe 上;不要将它困在 iframe 的窗口上;不要将它困在 iframe 的文档中。将其捕获<body>
在 iframe 内的文档元素上。很重要。
var iframe = your.rich.text.editor.getIframe(), // or whatever
win = iframe.contentWindow,
doc = win.document,
body = doc.body;
// Use your favorite library to attach events. Don't actually do this
// yourself. But if you did do it yourself, this is how it would be done.
if (win.addEventListener) {
body.addEventListener('paste', handlePaste, false);
} else {
body.attachEvent("onpaste", handlePaste);
}
请注意,我的示例代码附加了一个名为handlePaste
. 我们接下来会谈到这一点。粘贴事件很有趣:有些浏览器在粘贴之前触发它,有些浏览器在粘贴之后触发它。您需要对其进行规范化,以便您始终在粘贴后处理粘贴的内容。为此,请使用超时方法。
function handlePaste() {
window.setTimeout(filterHTML, 50);
}
因此,在粘贴事件后 50 毫秒,将调用 filterHTML 函数。这是工作的重点:您需要过滤 HTML 并删除任何不受欢迎的样式或元素。你在这里有很多事情要担心!
我个人在这些元素中看到过 MSWord 粘贴:
meta
link
style
o:p
(不同命名空间中的段落)
shapetype
shape
- 评论,喜欢
<!-- comment -->
。
font
- 当然,还有
MsoNormal
课堂。
filterHTML 函数应该在适当的时候删除这些。您可能还希望删除您认为必要的其他项目。这是一个filterHTML
删除我上面列出的项目的示例。
// Your favorite JavaScript library probably has these utility functions.
// Feel free to use them. I'm including them here so this example will
// be library-agnostic.
function collectionToArray(col) {
var x, output = [];
for (x = 0; x < col.length; x += 1) {
output[x] = col[x];
}
return output;
}
// Another utility function probably covered by your favorite library.
function trimString(s) {
return s.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
function filterHTML() {
var iframe = your.rich.text.editor.getIframe(),
win = iframe.contentWindow,
doc = win.document,
invalidClass = /(?:^| )msonormal(?:$| )/gi,
cursor, nodes = [];
// This is a depth-first, pre-order search of the document's body.
// While searching, we want to remove invalid elements and comments.
// We also want to remove invalid classNames.
// We also want to remove font elements, but preserve their contents.
nodes = collectionToArray(doc.body.childNodes);
while (nodes.length) {
cursor = nodes.shift();
switch (cursor.nodeName.toLowerCase()) {
// Remove these invalid elements.
case 'meta':
case 'link':
case 'style':
case 'o:p':
case 'shapetype':
case 'shape':
case '#comment':
cursor.parentNode.removeChild(cursor);
break;
// Remove font elements but preserve their contents.
case 'font':
// Make sure we scan these child nodes too!
nodes.unshift.apply(
nodes,
collectionToArray(cursor.childNodes)
);
while (cursor.lastChild) {
if (cursor.nextSibling) {
cursor.parentNode.insertBefore(
cursor.lastChild,
cursor.nextSibling
);
} else {
cursor.parentNode.appendChild(cursor.lastChild);
}
}
break;
default:
if (cursor.nodeType === 1) {
// Remove all inline styles
cursor.removeAttribute('style');
// OR: remove a specific inline style
cursor.style.fontFamily = '';
// Remove invalid class names.
invalidClass.lastIndex = 0;
if (
cursor.className &&
invalidClass.test(cursor.className)
) {
cursor.className = trimString(
cursor.className.replace(invalidClass, '')
);
if (cursor.className === '') {
cursor.removeAttribute('class');
}
}
// Also scan child nodes of this node.
nodes.unshift.apply(
nodes,
collectionToArray(cursor.childNodes)
);
}
}
}
}
您包含了一些您想要过滤的示例 HTML,但您没有包含您希望看到的示例输出。如果您更新您的问题以显示您希望您的样本在过滤后的样子,我将尝试调整 filterHTML 函数以匹配。目前,请将此功能视为设计您自己的过滤器的起点。
请注意,此代码不会尝试将粘贴的内容与粘贴之前存在的内容区分开来。它不需要这样做;它删除的东西无论出现在哪里都被认为是无效的。
另一种解决方案是使用正则表达式对innerHTML
文档正文过滤这些样式和内容。我已经走了这条路,我建议不要这样做,而支持我在这里提出的解决方案。您将通过粘贴收到的 HTML 会有很大差异,以至于基于正则表达式的解析将很快遇到严重问题。
编辑:
我想我现在明白了:您正在尝试自己删除内联样式属性,对吗?如果是这样,您可以在 filterHTML 函数中通过包含以下行来执行此操作:
cursor.removeAttribute('style');
或者,您可以针对特定的内联样式进行删除,如下所示:
cursor.style.fontFamily = '';
我更新了 filterHTML 函数来显示这些行的去向。
祝你好运,编码愉快!