24作者: panphora6 个月前原帖
嗨,HN!我对现代的所见即所得(WYSIWYG)编辑器感到非常沮丧,因此我开始尝试自己构建一个。 我遇到的问题很简单:我想要一种低技术的方式来输入格式化文本,但我不想加载一个复杂的500KB库,尤其是在同一页面上需要初始化多次的情况下。 在普通的 `<textarea>` 中使用 Markdown 是一个比完整 WYSIWYG 更好的替代方案,但它的主要缺点是没有任何格式时看起来很丑。我可以接受,但我的客户肯定无法接受。 我在可编辑内容(ContentEditable)方面探索了几年,但总是意识到别人解决这个问题的方式比我想象的要好得多。 我不断回到这个问题:为什么我不能拥有一个简单、高效、美观的 Markdown 编辑器?我见过的最好的解决方案是 Ghost 的分屏编辑器:左侧是 Markdown,右侧是预览,并且支持同步滚动。 大约一年前,我脑海中闪现了一个想法:如果我们在 `<textarea>` 后面叠加一个预览窗格会怎样?如果我们将它们完美对齐,那么即使你只是在编辑纯文本,它看起来和感觉起来也像是在编辑富文本! 当然,这样做会有一些缺点:你必须使用等宽字体,所有内容必须使用相同的字体大小,并且所有的 Markdown 标记必须在最终预览中显示。 但这些都是我可以接受的权衡。 总之,版本 1 的效果并不好……事实证明,保持 `<textarea>` 和渲染预览的对齐比我想象的要难。以下是我发现的问题: - 列表对齐困难 - 项目符号会影响字符对齐。通过使用保持等宽的 HTML 实体(• 作为项目符号)解决了这个问题。 - 并非所有等宽字体都是真正的等宽 - 即使在“等宽”字体中,粗体和斜体文本的宽度也可能不同,打破了完美的叠加效果。 - 嵌入是个噩梦 - 从父页面继承的任何 CSS(边距、内边距、行高)都会导致对齐偏移。即使是 1 像素的偏移也会彻底破坏这种错觉。 解决方案是进行强迫规范化: ```javascript // 整个技巧:在预览 div 上叠加一个透明的 textarea layerElements(textarea, preview) applyIdenticalSpacing(textarea, preview) // 使 textarea 隐形,但保持光标可见 textarea.style.background = 'transparent' textarea.style.color = 'transparent' textarea.style.caretColor = 'black' // 保持它们同步 textarea.addEventListener('input', () => { preview.innerHTML = parseMarkdown(textarea.value) syncScroll(textarea, preview) }) ``` 一周前,我开始尝试版本 2,并发现 GitHub 的 `<markdown-toolbar>` 元素,它在普通的 `<textarea>` 中处理 Markdown 格式化非常好。 这个实验变成了 OverType([https://overtype.dev](https://overtype.dev)),今天我向你们展示的就是这个——它是一个富 Markdown 编辑器,实际上只是一个 `<textarea>`。关键的见解是,一旦你解决了对齐问题,你就可以免费获得所有原生 textarea 提供的功能:撤销/重做、移动设备键盘、可访问性和原生性能。 到目前为止,它在各个浏览器和移动设备上表现得相当不错。我在一个小包(总共 45KB)中获得了高效的富文本编辑。这有点傻,但它确实有效!我计划在我所有的项目中使用它,并希望保持简单和简约。 如果你能试用一下,并告诉我你的想法,我会非常高兴。祝你编辑愉快! --- 演示和文档:[https://overtype.dev](https://overtype.dev) GitHub:[https://github.com/panphora/overtype](https://github.com/panphora/overtype)