我为我的平台的 XML (HTML5 + XHTML) 编辑目的创建了富编辑器。我不会说document.execCommand() 完全死了,因为它的某些部分仍然可以正常工作。不幸的是,对我来说主要问题是浏览器使用许多不同的代码来生成那些不被盲人或几乎盲人使用的屏幕阅读器识别的样式。
此外,我必须克服的最昂贵的时间错误是 Gecko/Presto 错误,其中视觉和技术选择(为什么它们不是同一件事,别问我)会导致 DOM 的一部分被改变了用户不打算这样做,这将归结为每个字符的像素数很低,因此如果富编辑器不尊重视觉选择,用户会很快走开。这需要 四个月 才能克服,而且还有其他错误。
最终这是一项艰巨但可以实现的努力,但如果你打算像我一样构建一个 HTML/XML 编辑器,你应该计划至少六个月,如果你不仅打算正确地完成它,而且要测试它到讨厌蛋糕的地步然后只有有人过来指出另一个错误。
您的 主要 JavaScript 重点应该放在以下方面:
代替使用来自不同浏览器的execCommand() 生成的不一致代码(通常设置内联样式,如果不完全否定它会使您网站的 CSS 复杂化),您应该坚持使用以下元素,您不仅可以控制这些元素虽然与屏幕阅读器兼容:
-
em 表示强调(或“斜体”,<i> 已弃用)。
-
strong 用于强读文本(或“粗体”,<b> 已弃用)。
-
u 用于下划线(确保您的锚点的样式与 u 元素区分开来;u 可能被视为“已弃用”,尽管我会在未来十年或所以,适当地使用它)。
-
sub 用于显示垂直低于正常文本的子行文本。
-
sup 用于垂直显示高于普通文本的超行文本。
- 不要不使用
<span>元素来专门添加这些样式,因为屏幕阅读器将不理解或揭示错误行为; 如果使用得当,它仍然是一个有效的通用内联元素。
实际上,我一直打算修改我的富编辑器(虽然尚未正确重写,但它已得到修补),尽管欢迎您在我的个人资料中链接的网站的博客页面上加载源代码时查看它。最初的项目花了我 11 个月,但根据我现在的经验,我认为我需要大约三到四个月。如果您是认真的,我强烈建议您远离框架和库。 “但是……但是,它们让生活更轻松!” ...直到您想使用新版本并且必须重写整个项目。第一次使用纯 JavaScript 并否定无意义的维护。祝你好运!
2021-09-24:我最终从大约一年前恢复了 Rich Editor II 的工作,并设法将更改样式的代码从 100,515 个字符转换为 ~6,000 个字符,并减少了文件请求(压缩后的有效带宽)整整三分之一。以下是成功的关键部分:
-
anchorNode 和 focusNode 可以根据您选择从左到右还是从右到左切换。因为我找不到任何理由说明为什么这很重要(对于我的平台),所以我在左侧创建了 an 对象(对于 anchorNode),并且始终在右侧创建了 fn 对象(对于 focusNode)一边。
-
我使用约 1,700 个字符解决了 Gecko/Presto 问题;您可以先在网站上找到它(访问具有丰富表单的页面)。
-
为了解决<s>、<sub>、<sup>、<u> 等通过大量交换选择的问题(您必须测试简单和非常复杂的示例)我最终使用window.getSelection().getRangeAt(0).commonAncestorContainer 和@987654362 @ 然后在处理之前 that 剥离了选择中未包含的内容。然后我简单地使用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 并跟踪更改的每次迭代,因此它仍然是一个庞大的项目。对于我的平台,现在没有必要,虽然我想介绍这一点,因为有些人在 cmets 中提到了它。