【高频考点精讲】手写动画函数:从requestAnimationFrame到缓动算法,实现流畅动画效果

手写动画函数:从requestAnimationFrame到缓动算法,实现丝滑动画效果

作者:全栈老李

更新时间:2025 年 5 月

适合人群:前端初学者、进阶开发者

版权:本文由全栈老李原创,转载请注明出处。

今天咱们聊聊前端动画那点事儿。不知道你们有没有遇到过这种场景:产品经理拍着桌子说"这个弹窗要优雅地淡入淡出",UI设计师拿着Figma指着某个按钮说"这里要有个灵动的弹性效果"。这时候如果你只会用CSS的transition和animation,可能就要被怼"太生硬了,不够丝滑"。(全栈老李就见过不少这样的翻车现场)

为什么不用CSS动画?

先别急着掏@keyframes,CSS动画确实方便,但遇到以下情况就力不从心了:

  1. 需要根据滚动位置实时计算动画进度
  2. 要和用户交互强关联(比如拖拽松手后的回弹)
  3. 要做复杂的物理效果(弹簧、引力等)
  4. 需要精确控制每一帧的逻辑

这时候就得请出我们的JavaScript动画三件套:requestAnimationFrame + 时间戳 + 缓动算法。

认识requestAnimationFrame

这货是浏览器专门为动画准备的API,比setTimeout不知道高到哪里去了。它的特点:

  • 会自动匹配显示器刷新率(通常是60fps)
  • 页面不可见时会自动暂停,省电
  • 回调函数接收高精度时间戳
// 全栈老李的RAF基础用法示例
function animate(timestamp) {
   
  // 在这里更新动画状态
  console.log(`当前帧时间戳:${
     timestamp}ms`);
  
  if (!animationComplete) {
   
    requestAnimationFrame(animate);
  }
}

// 启动动画
requestAnimationFrame(animate);

手写动画函数的核心逻辑

一个完整的动画函数需要处理这几个关键点:

  1. 持续时间:动画要播多久(200ms?500ms?)
  2. 进度计算:当前处于动画生命周期的哪个位置(0到1之间)
  3. 缓动函数:如何让运动更有质感(匀速?先快后慢?)
  4. 属性更新:根据进度计算具体属性值

来看个实战例子:

/**
 * 执行动画函数
 * @param {
     number} duration 动画持续时间(ms)
 * @param {
     function} easing 缓动函数
 * @param {
     function} update 属性更新函数
 * 全栈老李的动画核心实现
 */
function animate({
     duration, easing, update }) {
   
  const startTime = performance.now(); // 记录开始时间
  
  function run(time) {
   
    // 计算进度(0-1)
    let progress = <

你可能感兴趣的:(前端高频考点精讲,前端,javascript,html,css,面试题,react,vue)