☰
Tab Out 浏览器插件:Web Audio API 合成 Swoosh 关闭音效 + 纯 JS 彩纸粒子物理实战
2026/10/11 18:32:30 网站建设 项目流程

【免费下载链接】tab-out

Keep tabs on your tabs. Turn your "New tabs" page into a mission control, so you can close them easily. Built for people who open too many tabs and never close them.

项目地址:https://gitcode.com/gh_mirrors/ta/tab-out
点击查看免费下载

Tab Out 是一个 Chrome 浏览器插件,把"新标签页"变成所有已打开标签页的管控台:按域名分组、一键清理,关闭标签时还会播放一声清脆的 Swoosh 音效并炸出彩纸粒子。这篇文章带你拆透这两个"爽点"背后的技术——它不依赖任何音频文件,也不依赖任何动画库,音效由Web Audio API 实时合成,彩纸由纯 JavaScript 手写粒子物理驱动。全部实现都集中在 extension/app.js 里,代码量极小,非常适合新手学习。

💡 文中所有代码链接都指向仓库内的真实源码,你可以边读边对照,全程无需复制粘贴任何代码。

先看效果,再看源码在哪

在 Tab Out 里点一次"Close all N tabs",你会经历这么一套连招:

  1. 🎧 一声短促的"嗖——"(Swoosh)
  2. 🎊 卡片中心炸开 17 片彩纸,先抛起、后下落、渐渐淡出
  3. ✨ 卡片整体缩小淡出,屏幕下方弹出 Toast 提示

这三件事都由 extension/app.js 里的三个核心函数完成,行号可以直接跳转查看:

功能函数源码位置
Swoosh 合成音效playCloseSound()app.js#L298-L338
彩纸粒子系统shootConfetti(x, y)app.js#L347-L412
卡片关闭动画animateCardOut(card)app.js#L420-L431

为什么不用现成的 mp3 文件和彩纸库?因为这是一个零服务端、零依赖的纯插件(见 extension/manifest.json),作者坚持"能用几十行原生 API 解决的,绝不引入一个文件"。下面逐个拆解。

Swoosh 关闭音效:Web Audio API 四步合成法

很多人以为"嗖"的音效一定来自音频文件,其实它完全可以用数学公式"算"出来。playCloseSound() 的做法可以概括为四步合成:

第 1 步:用随机数"制造"白噪声

白噪声听起来像"沙沙"声——它就是把每秒几万个随机数直接当声音样本播放。代码先用AudioContext创建一个 0.25 秒的缓冲(ctx.createBuffer),然后循环填充随机样本。

第 2 步:给噪声画上"包络",让它像风掠过

裸白噪声又响又硬,难听。代码给每个样本乘上一个包络(envelope):前 10% 的时间音量快速爬升(快起音),剩下 90% 按 1.5 次方的曲线平滑衰减。这一步让噪声从"白噪音"变成了"空气流动"。

第 3 步:带通滤波器"扫频",制造嗖的感觉 🔑

这是整个音效的灵魂。噪声通过一个BiquadFilter 带通滤波器,而滤波器的中心频率在 0.25 秒内从4000Hz 指数下滑到 400Hz(exponentialRampToValueAtTime)。高频→低频的滑动,正是你听到"嗖——"时那种音调下滑的听感来源;Q 值 = 2.0则让滤波曲线足够"聚焦",声音干净不浑浊。

第 4 步:增益控制音量,用完即释放

最后用一个GainNode把整体音量压在 0.15(不吵人)再指数衰减到接近零,随后把"噪声源 → 滤波器 → 增益 → 扬声器"四个节点串成一条流水线播放。播放完 500ms,代码还会主动ctx.close()释放音频上下文——对插件这种"随时可能被调用"的场景,避免资源泄漏是个好习惯。整段调用外裹了一层try/catch:如果浏览器不支持 Web Audio,就静默失败,绝不影响关闭功能本身。

📌 小结:playCloseSound的配方 =白噪声 + 包络 + 扫频带通 + 音量衰减。把这四条曲线叠在一起,"嗖"就诞生了。同样的思路可以合成门轴声、翻页声、雨声——都是 Web Audio API 的基本功。

彩纸粒子物理:requestAnimationFrame 手写积分器

关掉标签时炸开的彩纸,由 shootConfetti(x, y) 实现。它没有用任何库,就是一个 60 帧/秒的手写粒子模拟,拆开看一共五个要素:

要素实现方式
粒子数量固定 17 片,保证"爆炸感"又不卡顿
外观8 色暖色调(琥珀 / 鼠尾草 / 石板 / 玫瑰),圆形与 2px 圆角方块各占一半,尺寸随机 5–11px
初始速度随机角度 0–360° × 随机速率 60–180,纵向额外向上偏置 -80(先抛起再落下)
重力恒定 200,位置公式y = vy·t + ½·g·t²——中学物理的匀加速运动直接照搬
生命周期随机 700–900ms,后半程透明度线性归零,时间到直接el.remove()

几个值得偷师的小细节:

  • 🌀方块会自旋,圆片不会。只有方形粒子叠加了rotate(elapsed × 200deg),因为圆旋转根本看不出来——写粒子特效时"只画看得见的运动",是省性能的关键。
  • 📍用transform移动而不是left/top。粒子用position: fixed钉在屏幕坐标,每帧只改transform和opacity,浏览器可以走合成器层,动画更顺滑。
  • 🧹闭包保存每个粒子的物理状态。角度、速度、重力都定义在粒子自己的作用域里,requestAnimationFrame回调里就地更新,粒子寿命结束即从 DOM 移除,没有全局数组要维护,天然无内存泄漏。
  • 🖱️pointer-events: none让彩纸飘过按钮时完全不干扰点击,体验细节很加分。

一次关闭动作的完整编排

音效和彩纸不是各自为政的,它们被统一编排进插件的事件委托体系里——整个 app.js 只有一个挂在document上的点击监听器,用data-action属性分发所有按钮行为。几个触发点对照:

  • 关闭单个标签(close-single-tab):先调 playCloseSound(),再在标签条中心调 shootConfetti(),标签条缩小淡出
  • 整组关闭(close-domain-tabs):音效 + animateCardOut() 在卡片中心炸彩纸,卡片 300ms 内缩小消失
  • 一键清空全部标签(close-all-open-tabs):一次音效,每张卡片都各炸一簇彩纸(app.js#L1423-L1429),像多米诺骨牌一样依次倒下,场面最壮观

卡片淡出的.closing样式由 extension/style.css 里的 CSS transition 完成(见 style.css#L263),关闭后若页面已无标签,还会弹出"Inbox zero, but for tabs"的空状态彩蛋(app.js#L450-L471)。

给新手的学习价值

这套效果组合拳最值得借鉴的,不是某个炫酷技巧,而是**"零依赖"的工程取舍**:

  1. 声音不用文件——Web Audio API 四步合成,一个 mp3 都不带;
  2. 动画不用库——一个requestAnimationFrame闭包就是完整的粒子物理引擎;
  3. 资源用完即走——音频上下文 500ms 后关闭,粒子到期即删 DOM,插件长时间挂着也不漏内存;
  4. 优雅降级——try/catch包住音频,不支持就静默跳过,核心功能不受影响。

如果你想在自己的项目里复刻"关闭/删除/完成"这类交互的爽感,直接对照 extension/app.js#L298-L412 这段 115 行的源码就够了:先学会用噪声+扫频合成 Swoosh,再把"初速度 + 重力 + 生命周期"三件套搬进你的粒子系统,就能得到一套体积几乎为零、手感却很精致的交互反馈。🚀

【免费下载链接】tab-out

Keep tabs on your tabs. Turn your "New tabs" page into a mission control, so you can close them easily. Built for people who open too many tabs and never close them.

项目地址:https://gitcode.com/gh_mirrors/ta/tab-out
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询