requestAnimationFrame 流畅动画原理详解:Fokus 缓动插值与渐入渐出代码深读

发布时间:2026/8/25 9:58:55
requestAnimationFrame 流畅动画原理详解:Fokus 缓动插值与渐入渐出代码深读 requestAnimationFrame 流畅动画原理详解Fokus 缓动插值与渐入渐出代码深读【免费下载链接】Fokus项目地址: https://gitcode.com/gh_mirrors/fo/FokusFokus 是一个仅 3kb、零依赖的文本高亮 JavaScript 库选中页面任意内容它就用半透明黑幕盖住其余部分。它的渐入渐出之所以丝滑秘诀全在requestAnimationFrame流畅动画循环与两套缓动插值公式里。本文带你完整拆解这套流畅动画原理几分钟读懂浏览器帧循环 指数缓动的实战写法。为什么 requestAnimationFrame 能让动画丝般顺滑 普通新手写动画最容易踩的坑是用setTimeout每隔 16 毫秒刷新一次画面。看似和屏幕 60Hz 刷新率一致实则毫无同步可言与刷新率天然对齐requestAnimationFrame会在浏览器下一次重绘前回调帧节奏由系统统一调度不会打架产生抖动后台自动降频页面切到后台时自动暂停回调省电又省 CPU避免重绘撕裂回调内的画面修改会合并到同一帧渲染不会出现画一半的撕裂帧。Fokus 的核心动画就是一个自我递归的redraw()函数它既负责画布又负责申请下一帧——这就是最经典的 rAF 动画循环。Fokus 的 rAF 动画循环一个 redraw() 走天下打开 js/fokus.js整个动画心脏就在redraw()里对应源码位置js/fokus.js#L86-L142。它每帧做三件事铺底色清空画布后用rgba(0,0,0, overlayAlpha)填满整个视口overlayAlpha就是黑幕的不透明度挖亮区用clearRect把当前透明区域那一块擦掉露出下方被高亮的文字申请下一帧只要还在选中状态或黑幕没完全褪完就继续requestAnimationFrame( redraw )js/fokus.js#L131-L140。两个容易忽略但极其重要的细节防帧重叠每次开新帧前先cancelAnimationFrame( redrawAnimation )js/fokus.js#L128。选区在鼠标移动中会频繁触发重绘取消旧帧能保证任何时刻只有一个循环在跑这是流畅动画的防抖自动停帧一旦黑幕完全消失且没有选区画布直接从 DOM 里移除动画循环彻底休眠不再消耗一帧资源。缓动插值深读神奇的 0.18 线性插值系数 ✨高亮框不是瞬移到选区上的而是每一帧都向目标靠近 18%。这段代码是全库的精髓js/fokus.js#L103-L106clearedRegion.left ( selectedRegion.left - clearedRegion.left ) * 0.18;这是标准的线性插值lerp追赶公式当前值 (目标值 - 当前值) × 系数。它的数学本质是指数趋近距离目标 100px 时本帧移动 18px距离剩 82px 时只移动约 14.8px越接近目标移动越慢视觉上就是先快后慢的减速缓动且永远不会过冲、天然平滑。 经验法则系数在 0.1 ~ 0.2 之间时动画在 60fps 下大约 1 秒内肉眼到位。Fokus 选 0.18恰好是轻快但不突兀的甜蜜点。还有一个贴心分支js/fokus.js#L96-L100黑幕渐入初期透明度 0.1会直接让透明区域瞬移到选区避免黑幕和方框各跑各的的割裂感——细节决定体感。渐入渐出深读同一变量两套完全不同的曲线黑幕透明度overlayAlpha的进出场用的是两条不对称曲线js/fokus.js#L118-L125阶段公式效果渐入overlayAlpha (0.75 - overlayAlpha) × 0.08朝目标透明度 0.75 缓慢趋近柔和淡入渐出overlayAlpha max(overlayAlpha × 0.85 - 0.02, 0)乘以 0.85 指数衰减再减 0.02快速褪色三个值得抄作业的技巧入缓出快渐入系数 0.08 比渐出衰减 0.85 更克制出现时含蓄、消失时干脆符合用户对遮罩的心理预期Math.max(..., 0)兜底指数衰减理论上永远到不了 0max强制归零配合循环终止条件保证动画一定会停不会无限残帧setTimeout( updateSelection, 1 )微延迟鼠标抬起后延迟 1ms 再更新选区js/fokus.js#L237确保浏览器先完成选中状态结算再启动动画避免首帧闪跳。兼容层没有 rAF 时的 16ms 降级方案Fokus 还自带了一段 requestAnimationFrame polyfilljs/fokus.js#L349-L372先探测webkitRequestAnimationFrame等厂商前缀版本全都找不到时用setTimeout按 16ms≈1/60 秒模拟一帧。这段 20 行代码是老旧环境下保持流畅动画的最小降级方案直接可以搬进你自己的项目。三个技巧带走自己写流畅动画的清单 ✅用 lerp 追赶代替计时器值 (目标 - 值) × 系数天然实现先快后慢无需计算总时长每个循环必须有可证伪的终止条件像overlayAlpha 0这样能归零判断才能让 rAF 循环自己停掉开新帧前先取消旧帧cancelAnimationFrame是防重绘冲突的保险丝。Fokus 的完整源码不到 400 行压缩版在js/fokus.min.js演示页入口为index.html样式见css/demo.css。把这 400 行读透你就掌握了浏览器流畅动画最核心的三块积木帧循环、缓动插值、渐入渐出。【免费下载链接】Fokus项目地址: https://gitcode.com/gh_mirrors/fo/Fokus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考