我打算使用 Document.execCommand()
方法以及 contenteditable
属性来构建我的自定义 WYSIWYG 编辑器。但是当我查看 Document.execCommand()
的 文档 时,我发现它现在已经过时了。它的现代(或现存)替代品是什么?
原文由 Omar 发布,翻译遵循 CC BY-SA 4.0 许可协议
我打算使用 Document.execCommand()
方法以及 contenteditable
属性来构建我的自定义 WYSIWYG 编辑器。但是当我查看 Document.execCommand()
的 文档 时,我发现它现在已经过时了。它的现代(或现存)替代品是什么?
原文由 Omar 发布,翻译遵循 CC BY-SA 4.0 许可协议
13 回答12.9k 阅读
7 回答2.1k 阅读
3 回答1.3k 阅读✓ 已解决
2 回答1.3k 阅读✓ 已解决
6 回答1.2k 阅读✓ 已解决
2 回答909 阅读✓ 已解决
3 回答801 阅读✓ 已解决
我为平台的 XML (HTML5 + XHTML) 编辑目的创建了 Rich Editor。我不会说
document.execCommand()
完全死了,因为它的某些部分仍然可以正常工作。不幸的是,对我来说主要的问题是浏览器使用许多不同的代码来生成那些盲人或接近盲人使用的屏幕阅读器 无法 识别的样式。此外,我不得不克服的最耗时的错误是 Gecko/Presto 错误,其中视觉和技术选择(为什么它们不是同一回事,别问我)会导致部分 DOM 被更改,以至于用户不打算这样做,这归结为每个字符的像素数很低,因此如果 Rich Editor 不 支持视觉选择,用户会很快走开。这需要 四个月 的时间才能征服,而且还有其他错误。
最终,这是一项艰巨但可以实现的努力,但如果你打算像我一样构建一个 HTML/XML 编辑器,你应该计划至少六个月,如果你计划不仅正确地做它,还要测试它到讨厌蛋糕的地步有人过来指出另一个错误。
明智的 JavaScript 主要 关注点应该在以下方面:
window.createRange()
window.createRange().surroundContents()
Node.cloneNode()
window.getSelection()
window.getSelection().getRangeAt(0).commonAncestorContainer
appendChild
insertBefore
insertBefore
+nextSibling
replaceChild
代替使用
execCommand()
从不同浏览器生成的不一致代码(通常设置内联样式,如果不完全否定它会使您网站的 CSS 复杂化),您应该坚持使用以下元素,您不仅可以控制这些元素尽管与屏幕阅读器兼容:em
强调(或“斜体”,<i>
已弃用)。strong
用于强读文本(或“粗体”,<b>
已弃用)。u
用于下划线(确保你的锚点的样式与 u 元素区分开来;u
可能 被视为“已弃用”,但我会在未来十年修复标准时扭转这一点左右,适当使用它)。sub
用于垂直显示低于普通文本的子行文本。sup
用于垂直显示高于普通文本的超行文本。<span>
元素来专门添加这些样式,因为屏幕阅读器将 无法 理解或揭示错误行为; _如果使用得当_,它仍然是一个有效的通用内联元素。实际上,我一直打算修改我的 Rich Editor(它已经得到修补,但尚未正确重写),尽管欢迎您在源代码加载到我个人资料中链接的站点的博客页面上时查看源代码。最初的项目花了我 11 个月,但根据我现在的经验,我认为大约需要三到四个月。如果你是认真的,我强烈建议你远离框架和库。 “但是……但是,他们让生活更轻松!” …直到您想使用新版本并且必须重写整个项目。第一次使用纯 JavaScript,拒绝无意义的维护。祝你好运!
2021-09-24:我从大约一年前开始恢复 Rich Editor II 的工作,并设法将更改样式的代码从 100,515 个字符转换为约 6,000 个字符,并将文件请求(压缩后的有效带宽)减少了整整第三。以下是成功的关键部分:
anchorNode
和focusNode
可以根据您选择从左到右还是从右到左进行切换。因为我找不到任何理由说明为什么这对我的平台很重要,所以我在左侧制作了an
对象(对于anchorNode
)和fn
对象(对于focusNode
)总是在右侧。我使用大约 1,700 个字符解决了 Gecko/Presto 问题;您可以先在网站上找到它(访问具有 Rich 表单的页面)。
To resolve the issue of selecting through numerous interchanges by
<s>
,<sub>
,<sup>
,<u>
etc (you must test both simple and wildly复杂的示例)我最终使用了window.getSelection().getRangeAt(0).commonAncestorContainer
和cloneNode
然后在处理 之前 去除了选择中未包含的内容。然后我简单地使用window.getSelection().deleteFromDocument();
删除选择并通过document.createElement
将其替换为新样式元素--- 我可以轻松地appendChild
并将其插入到window.getSelection().getRangeAt(0).insertNode(id_('editor_rich_text').firstChild);
选择---
。Gecko 浏览器,如 Waterfox、Pale Moon 和现在完全被摧毁的 Firefox,允许您选择多个文本实例。为此,只需按住
Control
键即可创建额外的选择。因为它并没有真正以任何有意义的方式提供帮助(而且这些东西已经够复杂了)我这次没有特意支持它。我将在今天或本周末(从这篇文章编辑开始)更新我的平台以反映新的变化。由于 Gecko 浏览器的许多问题,我保留了很多旧代码。我已经扩展了功能并解决了许多错误,并且不必求助于任何黑客,并且像往常一样没有车库(框架或库)。
2021-09-26:对于那些对重做/撤消功能感兴趣的人,您将不得不求助于基本上保留您正在编辑的 DOM 部分的文本版本。当然,可能还有其他方法来实现它,尽管这些方法会非常复杂。您基本上只是使用
.cloneNode
制作编辑器父元素的副本,然后当它在内存中时使用while (e.firstChild) {xml += new XMLSerializer().serializeToString(e.firstChild);}
的内容。由于您将把它存储为文本,因此它不会像 DOM 那样占用大量内存。您实际上是在编辑器中替换整个 DOM,并跟踪更改的每次迭代,因此它仍然是一个繁重的项目。对于我的平台,现在没有必要,尽管我想像一些人在评论中提到的那样介绍它。