欢迎回来
登录你的知识库账户
忘记密码?
还没有账户?立即注册
创建账户
注册你的专属知识库
已有账户?去登录
找回密码
输入注册邮箱获取验证码
返回登录
请输入图片中的验证码以继续注册
加载中...
取消
新建收藏
手动添加你喜欢的内容
取消
编辑头像与昵称
上传新头像或修改你的显示昵称
支持 JPG/PNG,最大 2MB
取消

问题反馈

notebasewww.notebase.cn
控制台
内容库
动态
管理
账户
U
用户
--
在线
v0.8.7 · 知识库
笔记
KnowledgeBase
网络无边,知识有迹。
0笔记
0工具
30推荐

分类导航

按主题直达

编辑精选

站内用户贡献 · 真实笔记

最新收录

每日更新
继续浏览全部内容 →
>
笔记
0
加载中...
工具
0
此页用于记录用户反馈问题后的每一次改进
笔记用法

“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。

md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。

要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。

工具用法

在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。

要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。

工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。

隐藏笔记

写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。

适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。

数据安全

你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。

技术

全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。

理念

这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。

原则

不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。

更多

产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。

举报

如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。

趋势
// 点击导航加载发现
归档
// 归档为空
最近浏览
// 暂无浏览记录
发布
// 加载中...
用户发布
// 加载中...
用户管理
// 加载中...
访问统计
// 加载中...
内容审核
// 加载中...
个人信息
// 加载中...
返回首页

从 Canvas 到 Textarea:一位工程师的自建文本编辑器技术选型实录

1970/1/1编程开发

本文记录了一位 Web 开发者在 2026 年基于浏览器技术自研文本编辑器的技术决策过程,对比了 Canvas、contenteditable 与 textarea 三种方案的性能与可访问性权衡。

缘起:软件垃圾时代的逆反

作者 David Bushell 在文章开篇引用自己之前一篇引起热议的短评——"他们不再像 Sublime Text 那样打造文本编辑器了"。他认为当前软件质量堪忧,而自己恰好擅长制造"垃圾",于是萌生了自建文本编辑器的念头。

他特别点名批評 VS Code:其底层核心 Monaco Editor 是一个基于 <div> 元素堆砌的"汤"。他的 Mac 在更换 Apple Silicon 之前性能太差,一直无法流畅使用 VS Code,直到换了新芯片才解决。如果 Monaco Editor 这种用 <div> 堆出来的编辑器都能成为业界标准,那自己试错的空间其实相当大。

第一轮实验:Canvas 渲染的一切

他的第一个实验是在一个 <canvas> 元素上渲染所有文本。虽然从视觉效果上看不出差别,但 CPU 实际上在拼命工作才能维持 60–120 fps 的刷新率。

Canvas 的低起点:Canvas 不会免费提供任何东西。他列出了"最小可行功能"清单并逐项实现:

  • 鼠标按下定位光标
  • 方向键移动光标
  • 高亮当前行
  • 输入文本
  • 光标动画效果

但这些只是冰山一角。他渴望的功能还包括:文本选择、撤销/重做历史、多行粘贴、溢出滚动。其中最关键的是溢出滚动——手动实现弹性滚动条太费人生,他决定作弊:用一个原生浏览器滚动元素。具体方案是:一个 <div> 尺寸与 Canvas 文本区域匹配,利用其原生滚动位置计算 Canvas 渲染的偏移量。

他承认这个方案进展不错,但也感到沮丧,因为 <canvas> 完全无法访问。即使继续添加文本选择等功能,也无法解决根本性的可访问性问题。于是他想到了更好的办法。

第二轮实验:contenteditable 的原生优势

他转而使用一个可滚动的原生 <div>,给它加上 contenteditable 属性。其中 plaintext-only 这个值特别适合代码编辑:内容始终保持在单个文本节点内。

html

必须显式关闭 autocapitalize、autocorrect、spellcheck、translate 等自动处理特性,否则会出现输入延迟峰值。作者透露:他花了好几天才发现这个关键点。

contenteditable 的好处:浏览器免费提供了原生文本选择、撤销历史、以及大量可访问性能力。他可以利用 Selection API 获取文本度量,继续自定义渲染文本光标;还可以用 ::selection 伪元素样式化选中区域。代价是必须把原生 caret 颜色设为不可见,这或许不算最佳实践,但功能可行。

性能瓶颈:尽管思路可行,但他发现当字符数超过一定阈值后会出现奇怪的性能问题。Chromium 系浏览器的表现比 WebKit 和 Firefox(无论现在叫什么)都要差,而且行为难以预测。

第三轮实验:textarea 的务实胜利

既然纯文本 contenteditable 有性能问题,那试试简单的 <textarea> 如何?答案是肯定的——<textarea> 在处理长文本时性能远优于 contenteditable,而且同样能获得所有原生好处。

语法高亮的实现:他原本计划用 CSS 的 ::highlight 来给 contenteditable 加高亮,但 <textarea> 无法使用 CSS 高亮,所以需要第三层叠加以实现可视化。他在最终演示中,为当前可视行增加了一些 <div> 容器,再借助 MicroLighter 库来实现语法高亮。

后续发展:作者补充说,后来得知新的 OpaqueRange API 可以为 <textarea> 解锁自定义高亮;此外 EditContext API 也改善了 <canvas> 的输入能力。但要注意:过多的 CSS 高亮也是一个性能瓶颈。更稳妥的方案是使用 Tree-sitter 生成语法树,只扫描并高亮当前可视行。

他原本希望完全避免虚拟滚动,但如果要突破性能极限,可以使用 sticky 技术优化可视区域渲染。或者干脆退回 contenteditable 方案——因为自己实际需要的文件规模并不会触发性能墙。

功能概览与未来边界

看起来这个编辑器已经像个文本编辑器了?他自嘲道:"看起来像 90% 的编辑器,但只有 1% 的功能。" 从这里继续补全功能是顺理成章的事,但他想到还有大量细节:比如 Tab 缩进——目前他只是劫持 Tab 键插入两个空格,但还没有处理多行缩进、自动缩进等复杂逻辑。

他在本文展示的演示代码离优雅和完全可访问还有距离,但至少不是从注定失败的起点出发。用 <canvas> 做文本编辑器简直是噩梦。他将这个项目归档为"雨天项目",等待将来某个下雨天再来完善。

彩蛋:JavaScript 字符串的 UTF-16 陷阱

文章最后他放出一个"程序员狙击"代码片段,提醒大家 JavaScript 字符串以 UTF-16 码元为单位,很容易踩坑:

javascript
"🍋🟩".length; // 5 (两个 emoji 各占 2 个码元,外加一个可变码元?实际是 2 个 UTF-16 码元,加上中间的变体选择符?——这里示例是 5)
[..."🍋🟩"].length; // 3 (展开运算符按码点拆分,得到 3 个码点)
const segmenter = new Intl.Segmenter("en", {granularity: "grapheme"});
[...segmenter.segment("🍋🟩")].length; // 1 (真正的用户感知字符,一个字形簇)

这段代码演示了对同一个字符串使用不同 API 得到的不同长度,直观地揭示了视觉上是一个"字符"的 emoji 在底层由多个码点组成。文本编辑器处理这类字符串时必须格外小心。

技术选型总结

方案 优点 缺点 适用场景
Canvas 完全定制渲染,视觉效果炫酷 无原生可访问性,所有功能需手动实现(选择、光标、滚动等),性能成本高(持续渲染) 图形编辑器、游戏,非通用文本编辑
contenteditable (plaintext-only) 原生文本选择、撤销、可访问性良好,单文本节点结构简单 长文本性能下降且浏览器间差异大 中小型代码块或文本编辑、富文本编辑器替代
textarea 性能最佳,原生滚动与选择,语义简单 无法用 CSS ::highlight,需要第三方高亮方案 长文本编辑、代码编辑器底层

最终作者放弃了纯 Canvas 路线,转而采用 textarea 作为渲染层,配合分层高亮方案,取得了最务实的平衡。

原文链接:Fine, I'll build my own text editor - David Bushell

编写使用方法
Markdown 格式 · Ctrl+Enter 确定
新建笔记
预览
数据表格
点击单元格编辑 · Tab 移动
A1fx
Sheet1
BIH1H2≡🔗</>
隐私提醒

取消
编辑工具
取消