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 页面留言。

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



Previous Post
今天,我第一次感受到了「实验室时刻」
Next Post
Inkflow Markdown:一次AI辅助开发的踩坑与实践之旅