限时福利领取


技术选型:三套方案的性能对决

先上测试数据(红米Note11T Pro/Chrome 108环境下):

  • CSS动画:实现20个烟花同时绽放时FPS降至24,GPU内存占用飙升
  • Canvas 2D:同场景稳定维持55FPS,但粒子数超过500时出现卡顿
  • WebGL:千级粒子量仍保持60FPS,但开发复杂度陡增

性能对比图

对于新手推荐Canvas方案,平衡了性能和实现难度。下面这段烟花基类代码展示了如何用TypeScript组织粒子系统:

interface Particle {
  x: number;
  y: number;
  vx: number;
  vy: number;
  radius: number;
  color: string;
  life: number;
}

class Firework {
  private particles: Particle[] = [];

  constructor(
    private ctx: CanvasRenderingContext2D,
    private config = {
      particleCount: 100,
      startColor: '#FF5E1A',
      endColor: '#FF00AA'
    }
  ) {}

  explode(x: number, y: number) {
    for (let i = 0; i < this.config.particleCount; i++) {
      this.particles.push({
        x, y,
        vx: Math.random() * 6 - 3,
        vy: Math.random() * -8 - 2,
        radius: Math.random() * 3 + 1,
        color: this.interpolateColor(
          this.config.startColor, 
          this.config.endColor,
          Math.random()
        ),
        life: 100
      });
    }
  }

  private interpolateColor(c1: string, c2: string, ratio: number) {
    // 颜色渐变算法实现...
  }
}

移动端适配的三大秘籍

  1. 动态Canvas尺寸:

    function resizeCanvas(canvas: HTMLCanvasElement) {
      const dpr = window.devicePixelRatio || 1;
      canvas.width = canvas.clientWidth * dpr;
      canvas.height = canvas.clientHeight * dpr;
      ctx.scale(dpr, dpr);
    }
  2. 性能分级策略:

    @media (max-width: 768px) {
      .firework {
        --particle-count: 50; /* 移动端减少粒子数 */
      }
    }
  3. 触控事件增强:

    canvas.addEventListener('touchstart', (e) => {
      e.preventDefault();
      const rect = canvas.getBoundingClientRect();
      fireworks.explode(
        e.touches[0].clientX - rect.left,
        e.touches[0].clientY - rect.top
      );
    });

移动端效果

性能优化实战技巧

对象池模式避免频繁创建销毁对象:

class ParticlePool {
  private pool: Particle[] = [];

  get(): Particle {
    return this.pool.pop() || {
      x:0, y:0, vx:0, vy:0, 
      radius:0, color:'', life:0
    };
  }

  release(p: Particle) {
    if (this.pool.length < 1000) {
      this.pool.push(p);
    }
  }
}

帧率控制确保流畅度:

let lastTime = 0;
function animate(time: number) {
  if (time - lastTime > 16) { // 约60FPS
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    updateParticles();
    lastTime = time;
  }
  requestAnimationFrame(animate);
}

血泪教训:iOS的特别关照

  • Canvas内存限制:iOS会强制回收超过1024x1024的Canvas
  • 解决方案:
    function isIOS() {
      return /iPad|iPhone|iPod/.test(navigator.userAgent);
    }
    
    if (isIOS()) {
      config.maxParticles = 300; // iOS端降低复杂度
    }

完整示例与思考题

在线Demo 包含所有示例代码。

最后抛个思考题:如果要实现「手机扫码同步观看烟花」的互动效果,你会怎么设计通信方案?欢迎在评论区讨论!

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐