MMyBlog
← 返回博客
前端
10 分钟·3,724 ·60 次阅读

粒子实验室与光标交互:Canvas 动效组件拆解

📌 学习地址(点击可直接体验):粒子实验室 · 高级光标交互演示

两个单文件 HTML 里的前端动效组件

最近我在整理前端动效学习资料时,做了两个零依赖的单文件演示页面:一个"粒子实验室",一个"高级光标交互演示"。它们各自把几种炫酷的交互效果集中在一个 HTML 里,做的时候发现,这些效果看起来复杂,拆开看核心思路都特别简单——无非是监听鼠标位置、用 Canvas 或 CSS 变量画东西、再用 transform 走 GPU 渲染。

这篇文章把两个页面里的组件逐个拆解一遍,记录每个组件背后的关键技术点。这些技巧以后做个人主页、作品集或产品落地页时大概率用得上。

粒子实验室:Canvas 粒子系统的四种玩法

粒子实验室里有四个独立的粒子效果,全都是 Canvas 2D 画出来的。

粒子实验室
├── 星座网络背景 —— 粒子间连线,形成网状背景
├── 点击粒子爆裂 —— 点击处迸发一圈粒子
├── Gooey 液态流体 —— SVG 滤镜让圆球像水银一样粘连
└── 万有引力场 —— 点击添加引力星,粒子被吸引

星座网络背景

这是很多个人主页都在用的经典背景:屏幕上散布着缓慢飘动的粒子,距离近的粒子之间会连一条线,整体像星空连线图。实现核心是两层循环——外层遍历每个粒子,内层计算它和其余粒子的距离,小于阈值就画线。为了性能,通常只比较相邻格子里的粒子(空间划分),避免 O(n²) 的全量计算。

Gooey 流体

这是最"魔法"的一个效果,但原理出奇简单。它没有用任何物理模拟,而是靠 SVG 滤镜里的两个原语:先用 feGaussianBlur 把图形高斯模糊,再用 feColorMatrix 拉高对比度,模糊的边缘就被"切"回了清晰的边界。几个圆形在模糊+高对比的组合下,视觉上就像水银一样互相融合、拉扯。

Gooey 液态的滤镜链路
├── 原始图形(多个圆形)
├── feGaussianBlur —— 高斯模糊,边缘糊开
└── feColorMatrix —— 高对比度,把糊边切回清晰
     → 结果:圆形之间出现"粘连"的液态过渡

引力场模拟

最后一个引力场是可以交互的:点击添加一个引力星,粒子被引力吸引过去;拖动引力星,粒子跟着改方向;双击清空。这里的物理模型和弹簧小球类似——粒子每帧受到指向引力星的加速度,速度累加、位置更新,再乘个阻尼系数防止越转越快。

一、自定义光标:lerp 惯性跟随

高级光标演示里最抓眼球的,是那个"追着鼠标跑"的自定义光标。它由两部分组成:一个实心小点紧跟鼠标,一个空心圆环慢半拍,形成拖尾惯性。

让环"慢半拍"的核心,是一行叫 lerp(线性插值)的公式:

dx += (mx - dx) * 0.5;   // 点:靠近 50%,跟手快
rx += (mx - rx) * 0.14;  // 环:靠近 14%,跟手慢 → 拖尾感

系数越接近 1 跟得越紧,越接近 0 惯性越明显。环还用 mix-blend-mode: difference,划过任何颜色背景都自动反色,始终清晰。

二、磁性按钮:双层位移

鼠标靠近按钮,按钮会"迎上去",鼠标在按钮上移动时按钮跟着微微偏移。诀窍是内外层用不同系数:

btn.style.transform = `translate(${x * 0.3}px, ${y * 0.3}px)`;   // 外层
inner.style.transform = `translate(${x * 0.55}px, ${y * 0.55}px)`; // 内层文字

内层位移更大,形成"文字比外壳更贴近鼠标"的视差,比整体一起动立体得多。

三、聚光灯卡片:CSS 变量 + radial-gradient

鼠标移到卡片上,卡片表面亮起一束光跟着鼠标走。实现只改两个 CSS 变量:

card.style.setProperty('--mx', (e.clientX - rect.left) + 'px');
card.style.setProperty('--my', (e.clientY - rect.top) + 'px');
.spotlight-card::before {
  background: radial-gradient(420px circle at var(--mx) var(--my),
              rgba(255,255,255,0.18), transparent 70%);
}

全程只改两个变量,浏览器只需重绘那一个渐变层,性能开销极小。

四、3D 视差倾斜:perspective + 分层

卡片跟着鼠标"转动",内部文字、角标在不同深度形成立体视差。

const px = (e.clientX - rect.left) / rect.width - 0.5;   // -0.5 ~ 0.5
tilt.style.transform = `rotateY(${px * 16}deg) rotateX(${-py * 16}deg)`;

外层容器要设 perspective: 900px,内部元素用 translateZ 拉开深度(文字 40px、角标 55px),透视效果才出得来。

五、弹簧小球:弹簧物理 + 弹性形变

小球用弹簧物理追鼠标,速度越快拉伸越明显。

ball.vx += (ball.tx - ball.x) * 0.055;   // 弹簧拉力
ball.vx *= 0.82;                          // 阻尼
ball.x += ball.vx;

速度越大拉伸越大,配合旋转和缩放形成"squash & stretch"的弹性质感——迪士尼动画十二原则之一。

性能优化的共同原则

两个页面所有动效都遵循几条性能铁律:

├── requestAnimationFrame 驱动 —— 与屏幕刷新同步
├── CSS 变量写入 —— 只改变量,浏览器只重绘相关层
├── transform / Canvas —— 走 GPU,不触发 layout
├── passive 事件 —— 不阻塞滚动
├── devicePixelRatio 适配 —— 高分屏不糊
└── 只在桌面(hover: fine)设备启用光标类效果

最关键的一条是"用 transform 而不是 width/left/top"——transform 只走合成阶段,不触发布局和重绘,这是前端动画流畅的基石。

写在最后

这两个页面把粒子系统、Gooey 流体、引力场、自定义光标、磁性按钮、聚光灯、3D 视差、弹簧小球八种交互塞进了零依赖的单文件 HTML 里。背后的技术——lerp、mix-blend-mode、SVG 滤镜、CSS 变量、perspective、弹簧物理——单拎出来任何一个都是前端动效的基本功。

建议用桌面浏览器点开两个学习页,亲手体验每种效果的手感:

👉 粒子实验室 · 高级光标交互演示

移动鼠标、点击画布、拖动引力星,感受粒子系统和光标交互的差异。这些组件以后做个人主页或项目展示时,稍加改造就能直接复用。

文章链接: