我为我的平台创建了一个丰富的编辑器,用于XML(HTML5 + XHTML)编辑目的。我不会说document.execCommand()已经完全死亡,因为它的某些部分仍然可以正常工作。不幸的是,对我来说,主要问题是浏览器使用许多不同的代码来生成那些屏幕阅读器无法识别的样式,这些阅读器被盲人或近乎盲人使用。
此外,我曾经遇到过最昂贵的时间错误是Gecko/Presto错误,其中视觉和技术选择(为什么它们不是同一件事,请不要问我)将导致DOM的某些部分被更改,而用户并没有打算这样做,这归结于每个字符的像素计数较低,因此如果Rich Editor不尊重视觉选择,用户很快就会离开。这需要四个月的时间才能克服,还有其他的错误。
最终,这是一个艰苦但可实现的努力,如果你打算像我一样构建一个HTML/XML编辑器,你应该计划至少六个月的时间,如果你不仅要做得正确,而且要测试到讨厌蛋糕的程度,然后只有有人指出另一个错误。
你的JavaScript方面的主要重点应该是以下内容:
document.createRange()(创建 Range 对象)
document.createRange().surroundContents()(包裹范围内的所有节点)
Node.cloneNode()(复制节点)
window.getSelection()(获取用户选择的文本)
window.getSelection().getRangeAt(0).commonAncestorContainer(获取选区公共祖先节点)
appendChild(在父节点末尾插入子节点)
insertBefore(在指定节点之前插入子节点)
insertBefore + nextSibling(在指定节点之后插入子节点)
replaceChild(替换子节点)
使用execCommand()从不同的浏览器生成的代码不一致(通常设置内联样式,如果不彻底否定它,则会使您网站的CSS变得复杂),您应该坚持使用以下元素,您不仅可以控制,而且还与屏幕阅读器兼容:
em 用于强调文本(或“斜体”,已被弃用)。
strong 用于强烈的文本(或“粗体”,已被弃用)。
u 用于下划线(确保您的锚点样式与元素不同;u可能被认为是“已弃用”的,但当我在未来十年左右修复标准时,我会反转这一点,适当使用它)。
sub 用于垂直低于正常文本的子行文本。
sup 用于垂直高于正常文本的上行文本。
请勿使用元素特别添加这些样式,因为屏幕阅读器将无法理解或显示错误行为;当适当使用时,它仍然是一个有效的通用内联元素。
我一直打算修改我的富文本编辑器 (虽然它已经得到了修补,但还没有被彻底重写),但你可以在我个人资料中链接的网站上加载博客页面时查看源代码。原始项目花费我11个月的时间,但是现在有了更多的经验,我认为只需要三到四个月的时间就可以完成。如果你是认真的,我强烈建议远离框架和库。"但是…但是,他们会使我的生活变得更轻松!" 直到你想使用新版本并不得不重写整个项目。第一次使用纯 JavaScript 并避免无意义的维护。祝你好运!
2021年9月24日:我最终重新开始了大约一年前的Rich Editor II工作,并成功将改变样式的代码从100,515个字符转换为约6,000个字符,并将文件请求(压缩后的有效带宽)减少了三分之一。以下是成功的关键部分:
anchorNode和focusNode根据从左到右或从右到左选择而切换。因为我在我的平台上找不到任何理由说明这很重要,所以我将an对象(代表anchorNode)放在左边,将fn对象(代表focusNode)始终放在右边。
我使用了约1,700个字符来解决Gecko/Presto问题;您可以先访问一个具有丰富表单的页面,在网站上找到它。
为了解决通过、、、等多种交换选择的问题(您必须测试简单和非常复杂的示例),我最终使用了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年9月26日:对于那些对撤销/重做功能感兴趣的人,你们将不得不使用基本上保留正在编辑的DOM部分的文本版本。当然,也可能有其他实现方式,但这些方式会非常复杂。你只需要使用 .cloneNode 制作编辑器父元素的副本,然后在内存中使用类似于 while(e.firstChild){xml + = new XMLSerializer().serializeToString(e.firstChild);} 的东西。由于您将其存储为文本,因此它不会具有DOM所具有的巨大内存影响。您将完全替换编辑器中的整个DOM,并跟踪每次更改的每个迭代,因此它仍将是一个庞大的项目。对于我的平台来说,现在并不是必要的,但我想提一下这一点,因为有些人在评论中提到了它。