前端面试之弹幕功能设计与实现

70 阅读2分钟

本篇简单聊聊前端面试中在react项目中 弹幕 的实现和架构设计

功能

  1. 弹幕从右侧出现,向左移动,直到完全离开屏幕。
  2. 通过定时器或requestAnimationFrame更新弹幕位置。
  3. 弹幕的渲染可以使用DOM元素,也可以使用Canvas绘制。
  4. 支持不同颜色、样式的弹幕。
  5. 支持弹幕的暂停、继续、清除。
  6. 支持弹幕发送。

设计

  • 将弹幕功能拆分为几个部分:弹幕数据管理、弹幕渲染、弹幕动画控制。

  • 使用Context或Redux管理弹幕数据状态,便于组件间通信。

  • 弹幕渲染使用Canvas还是DOM?根据性能需求选择。如果弹幕数量大,使用Canvas性能更好;如果数量不多,使用DOM更灵活。

  • 弹幕动画使用CSS3动画或requestAnimationFrame,保证流畅性。

// 弹幕系统架构
class DanmakuSystem {
  constructor() {
    this.channels = [];      // 弹幕轨道
    this.pool = [];          // 弹幕对象池
    this.isPlaying = false;  // 播放状态
  }
}

// React组件结构
function DanmakuContainer() {
  return (
    <DanmakuContext.Provider value={danmakuStore}>
      <VideoPlayer />
      <DanmakuInput />
      <DanmakuDisplay />
      <DanmakuControl />
    </DanmakuContext.Provider>
  );
}

代码实现思路

  • 弹幕数据通过WebSocket或轮询从服务器获取,然后存储在状态管理中。

  • 弹幕组件从状态管理中获取弹幕数据,然后渲染到屏幕上。

  • 每个弹幕元素绝对定位,从右侧移动到左侧,移动速度可控制。

  • 为了避免重叠,可以采用轨道机制,将屏幕分为多个轨道,弹幕按轨道发射。

// 弹幕核心逻辑
function useDanmaku() {
  const [danmakus, setDanmakus] = useState([]);
  const containerRef = useRef();
  
  // 添加弹幕
  const addDanmaku = useCallback((text, options = {}) => {
    const danmaku = {
      id: generateId(),
      text,
      color: options.color || '#fff',
      speed: options.speed || 1,
      timestamp: Date.now(),
      position: calculatePosition() // 计算轨道位置
    };
    
    setDanmakus(prev => [...prev, danmaku]);
  }, []);
  
  // 弹幕动画
  useEffect(() => {
    const animate = () => {
      setDanmakus(prev => 
        prev.map(danmaku => ({
          ...danmaku,
          left: danmaku.left - danmaku.speed
        })).filter(danmaku => danmaku.left > -100) // 移除屏幕外的弹幕
      );
      requestAnimationFrame(animate);
    };
    
    animate();
  }, []);
  
  return { danmakus, addDanmaku, containerRef };
}
// 弹幕管理系统
class DanmakuManager {
  // 1. 轨道管理
  allocateChannel(danmaku) {
    // 寻找合适的轨道,避免重叠
    for (let i = 0; i < this.channelCount; i++) {
      if (this.isChannelAvailable(i, danmaku)) {
        return i;
      }
    }
    return -1; // 没有可用轨道
  }
  
  // 2. 碰撞检测
  isChannelAvailable(channel, newDanmaku) {
    const existing = this.getChannelDanmakus(channel);
    return existing.every(danmaku => 
      !this.willCollide(danmaku, newDanmaku)
    );
  }
  
  // 3. 速度控制
  calculateSpeed(danmaku) {
    const baseSpeed = 2;
    const lengthFactor = danmaku.text.length / 10;
    return baseSpeed * (1 + lengthFactor * 0.2);
  }
}

总的来说,弹幕功能包含三个主要方面,分别是 数据状态管理、弹幕渲染、弹幕动画控制