Anton Medvedev 开发的 textarea.my 是一个完全运行在浏览器中、将所有内容存储在 URL hash 中的极简文本编辑器。虽然只有约 160 行代码,但它巧妙运用了 contenteditable="plaintext-only"、CompressionStream、文件系统 API 以及优雅的防抖函数,是学习现代 Web 开发技巧的绝佳范例。
极简之美:textarea.my
最近,知名技术博主 Simon Willison 推荐了一个名为 textarea.my 的项目。这是由 Anton Medvedev 开发的一款极简文本编辑器。
它的核心理念非常独特:完全在浏览器中运行,并将所有数据存储在 URL 的 hash 中。
更令人惊叹的是,实现这一切仅仅用了约 160 行 HTML、CSS 和 Javascript 代码。Simon Willison 直言:“非常值得一读,我从中通过学到了很多巧妙的技巧!”
让我们一起来看看这个小项目里藏着哪些大智慧。
核心技术亮点
1. contenteditable="plaintext-only"
你可能知道 contenteditable="true",但你听说过 plaintext-only 吗?
<article contenteditable="plaintext-only">这是一个相对较新的属性值,目前已在所有现代浏览器中得到支持。它允许元素可编辑,但强制内容为纯文本,避免了传统 contenteditable 常常带来的富文本格式混乱问题。这是一个非常实用但常被忽视的特性。
2. 基于 URL 的状态存储与压缩
为了将编辑器内容完整地保存在 URL 中(并在长度允许范围内),该项目使用了 CompressionStream API:
new CompressionStream('deflate-raw')通过 deflate-raw 算法对编辑器状态进行压缩,使其能够塞进更短的 URL 片段(Fragment)中。这意味着你可以通过复制 URL 来分享你的文档,而无需任何后端数据库支持。
3. 智能的文件保存机制
项目实现了一个巧妙的自定义保存功能,当用户按下 Cmd+S 或 Ctrl+S 时触发:
((e.metaKey || e.ctrlKey) && e.key === 's')- 对于支持的浏览器(主要是 Chrome 及其变体):它会调用现代的文件系统访问 API window.showSaveFilePicker(),允许用户直接保存到本地文件系统。
- 对于其他浏览器:则回退到传统的下载方式。
两种方式都通过以下代码生成文件内容:
URL.createObjectURL(new Blob([html], {type: 'text/html'}))4. 优雅的防抖(Debounce)函数
Simon Willison 特别点名表扬了该项目中 debounce() 函数的实现,称其为“真正的优雅”。
function debounce(ms, fn) { let timer return (...args) => { clearTimeout(timer) timer = setTimeout(() => fn(...args), ms) }}代码解析: debounce(ms, fn) 的作用是接收一个函数和一个超时时间(例如 100ms),并确保该函数在规定时间内最多只运行一次。
这个实现利用了闭包(Closure)变量 timer 来捕获 setTimeout 的 ID。
- 机制:当函数被连续调用时,上一次的定时器会被 clearTimeout(timer) 取消,随后一个新的定时器会被创建。
- 效果:如果你快速连续调用该函数 5 次,它只会执行一次——即在最后一次调用后的 100ms 时执行。
这种简洁的实现方式非常利于理解闭包和高阶函数的实际应用。
️ 笔者锐评
在如今这个动辄数百兆依赖、复杂框架横行的前端开发时代,textarea.my 就像一股清流。它提醒我们:Web 平台本身已经足够强大。
很多时候,我们为了解决一个简单的问题引入了过度的复杂性。160 行代码就能实现一个带压缩、持久化(URL)、本地保存功能的编辑器,这不仅是技术展示,更是一种工程哲学的回归。对于国内开发者而言,是否也应该在“一把梭”之前,多思考一下原生 API 的可能性?有时候,少即是多(Less is More)。
求点赞 求关注 ❤️ 求收藏 ⭐️ 你的支持是我更新的最大动力!
