Skip to content
Go back

我的油猴脚本开发日记:复刻 PopClip “Large Type” 功能的心路历程

Published:  at  07:30 PM

大家好,我是Byron。如果你经常在不同设备间切换,或者像我一样,对某些特定平台上的小功能“爱不释手”,那么你可能会理解我今天想分享的这份心情。最近,我完成并发布了一个小小的油猴脚本——Large Type Display,它的核心功能,是复刻 macOS 上广受好评的 PopClip 工具中的“Large Type”(大字体显示)特性。

这篇博客,我想把这次“为爱发电”的开发经历记录下来,特别是其中遇到的两个不大不小的“坑”以及我是如何一步步把它们填平的。希望能给同样热爱折腾、喜欢用代码解决实际问题的朋友们带来一些共鸣和启发。

目录

Open 目录

灵感闪现:那个 macOS 上的“大字”诱惑

故事的开头,得从 macOS 上的 PopClip 说起。用过 Mac 的朋友,很多都对这个小巧的文本工具赞不绝口。PopClip 有个功能叫“Large Type”,选中一段文字,轻轻一点,文字就能“唰”地一下以巨大的、清晰的字体全屏显示。这个功能在很多场景下都特别实用:比如你想把屏幕上的小字看得更清楚,或者想快速把一段信息展示给旁边的同事。

Inkflow Markdown Editor

macOS PopClip 的 Large Type 功能(示意图)

然而,当我切换到 Windows 环境,或者在 Linux 上工作时,这份便利就消失了。我开始琢磨:“万能的油猴(Tampermonkey)是不是可以帮我实现这个愿望,让所有浏览器都能用上类似的功能呢?” 这个念头一旦萌生,就有点一发不可收拾了。

初版诞生:从想法到看得见的“雏形”

万事开头难,但对于这种目标明确的小工具,快速搭建一个原型还是比较顺利的。我的初步构想很简单:

  1. 用户在网页上用鼠标选中一段文本。
  2. 按下预设的快捷键。
  3. 脚本动态创建一个覆盖全屏的 div 作为蒙版。
  4. 将选中的文本内容放入这个蒙版中,并用 CSS 设置一个较大的固定字体(比如 8vw)。

三下五除二,基础的 HTML 结构、CSS 样式和 JavaScript 核心逻辑很快就位。当第一次成功选中文字,按下快捷键,看到选中的内容真的以大字体弹了出来——尽管还很粗糙,蒙版简陋,字体大小也远谈不上完美——但那种“It works!”的喜悦,相信每个开发者都懂。

第一个“拦路虎”:快捷键为何“纹丝不动”?

正当我沉浸在初步成功的喜悦中,准备进一步打磨功能时,第一个“拦路虎”不期而至。我给脚本设置的默认快捷键是 Alt + D。但在某些情况下(尤其是我最初在 macOS 上用 Chrome 测试,后来发现某些 Windows 的键盘布局或输入法状态也可能触发),这个快捷键就像“失灵”了一样,按下去毫无反应。

“代码逻辑看起来没问题啊,监听器也加上了,怎么回事?” 我挠了挠头,祭出了前端开发的老朋友——console.log()大法。我把键盘事件对象 event 里的各种属性,特别是 event.key, event.altKey, event.ctrlKey 等,一股脑儿全打印出来。

很快,问题暴露了:当我按下 Alt + D 时,在某些环境下,event.key 的值并不是我期望的 d 或者 D,而是一个奇怪的 符号(偏导数符号,这是 macOS 上 Option + D 的默认输入)。我的脚本里判断 event.key.toUpperCase() === 'D' 自然就“扑街”了。

解决方案: 经过一番查阅,我了解到 event.key 返回的是按键产生的“字符”,会受到修饰键(如 Alt/Option)和键盘布局的影响。而 event.code 属性则更能代表键盘上物理按键的“代码”,比如字母“D”键对应的就是 KeyD。于是,我果断将快捷键的判断逻辑从:

if (event.altKey && event.key.toUpperCase() === currentShortcutKey.toUpperCase() && ...)

修改为:

if (event.altKey && event.code === 'Key' + currentShortcutKey.toUpperCase() && ...)

问题迎刃而解!无论 Alt + D 最终输入的是什么字符,只要用户确实按下了物理上的 Alt 键和 D 键,脚本就能正确响应。

小结: 这个小波折提醒我,看似简单的浏览器事件,其内部属性和跨平台表现也可能充满“细节”。对于需要精确捕获用户按键的场景,event.code 往往比 event.key 更可靠。

第二个挑战:如何让文字“恰到好处”地铺满屏幕?

快捷键的问题解决了,我开始聚焦核心体验——如何让大字体显示得“恰到好处”。我最初用的是 CSS 的 vw (viewport width) 单位来定义字体大小,比如 font-size: 8vw;。这种方式能让字体随着浏览器窗口宽度变化,有一定响应性。

但很快我就不满意了:

选几个字时:比如选中 “你好” 这两个字,8vw 的大小虽然比原文大了不少,但放在整个屏幕中央,还是显得“空落落”的,不够突出,没有那种“全屏放大”的冲击力。 选一大段文字时:如果选了几百个字,8vw 可能又导致文本行数过多,整体高度超出屏幕,或者因为 line-height 的累积,内容显示不全。 我理想中的效果是:当选中的文字很少(比如一个单词或短语),字体应该变得巨大无比,几乎撑满屏幕的宽度或高度;当选中的文字很多时,字体则应自动缩小,以确保内容能清晰、完整地在屏幕内展示。这显然不是一个固定的 vw 值或者简单的几档媒体查询能完美解决的。

攻坚之路:让 JavaScript 赋予字体“灵魂”

我很快意识到,单靠 CSS 的 vw 单位和媒体查询,是喂不饱我这个“既要…又要…”的贪心需求的。要想让字体大小能同时兼顾文本长短和屏幕尺寸,做到真正的“量体裁衣”,还得请 JavaScript 出马。

我的核心思路其实也挺“朴素”:

大胆假设(一个超大字号):脚本会根据你选中的文字有多少,先在心里估摸一个比较“奔放”的初始字体大小(用像素 px 做单位,这样控制起来更精确)。如果字少,这个初始值就尽量往大了猜,目标就是“铺满它”! 小心求证(字体能塞得下吗?):然后,脚本会把这个“奔放”的字号“穿”在你的文字上,再悄悄地测量一下,看看这些文字实际占了多宽、多高(这里用到了 scrollWidth 和 scrollHeight 这两个属性,为了测得准,我还得确保每次都是在一个“干净”的容器里进行测量)。 不断试探(逐步调整到完美):如果发现文字“胖”得快把屏幕(准确说,是预留给它显示的那块区域,大概是屏幕宽高的85-90%)给撑破了,那就说明初始字号太“浪”了,得收敛点。别急,脚本会自动、而且非常快速地一点点把字号调小,调小一点,再量一下,又超了?再调小一点,再量一下……就这样循环往复,直到文字不多不少、刚刚好能舒适地待在屏幕里,或者已经缩小到了一个我们能接受的最小阅读字号为止。 整个过程听起来可能有点像“机器人试衣服”,但对电脑来说就是一瞬间的事儿。调试这个“自动试穿并调整大小”的逻辑确实花了不少心思,尤其是要平衡好初始字号的“奔放”程度和缩小调整时的“小碎步”幅度。目标就是,既要让一两个字的时候,字体能“Duang”一下放大,带来视觉冲击;又要保证一大段“小作文”也能优雅地缩小,清晰完整地呈现出来。

当最终看到,无论是寥寥数字,还是一大篇文章,都能在屏幕上以近乎完美的姿态动态适应、时而霸气侧漏、时而温婉如玉时,那种“成了!”的舒畅感,嗯,就是内个味儿!之前挠破头皮想的各种细节、尝试的各种参数,在那一刻都值了!

小细节与“公之于众”

核心功能稳定后,我还做了一些锦上添花的工作:

使用 GM_registerMenuCommand 添加了自定义快捷键的功能,用户可以在油猴菜单中修改触发字母,增加了脚本的灵活性。 给覆盖层的出现和消失加入了一些简单的 CSS 过渡动画,让体验更平滑一点。 一切就绪,我把脚本命名为 “Large Type Display”,整理好元数据和描述,将它发布到了 Greasy Fork。这是我第一次正儿八经地发布一个自己从头写的油猴脚本,心情还是有点小激动的。

一些心得与未来

这次开发“Large Type Display”的经历,虽然只是一个小工具的诞生过程,但对我而言是一次宝贵的实践和学习。

如果你也对这个脚本感兴趣,或者在日常中常常有放大屏幕文字的需求,欢迎前往 Large Type Display 下载体验。有任何建议或 Bug 反馈,都可以在 Greasy Fork 页面留言。

感谢你的阅读,希望这篇开发日记能给你带来一点点启发或乐趣!



Next Post
Inkflow Markdown:一次AI辅助开发的踩坑与实践之旅