《打造丝滑视频切换组件:从预加载到无缝过渡的全实践》

222 阅读2分钟

前言

在视频类网站和应用中,如何实现视频间的无缝切换一直是提升用户体验的关键。本文将带你实现一个支持预加载、进度保持和丝滑过渡的视频切换组件,解决视频播放中的卡顿问题。

一、需求分析与设计思路

核心需求

  1. 预加载机制:提前加载下一个视频
  2. 进度保持:切换时保留播放进度
  3. 无缝过渡:视频间平滑切换效果
  4. 内存管理:及时清理不用的视频元素

技术选型

  • 使用Class封装核心逻辑
  • 私有字段管理内部状态
  • DOM操作实现视频切换
  • 预加载优化体验

二、核心实现解析

export default class SwitchVideo {
  // 私有字段
  #videoNames;    // 视频名称列表
  #nextVideo = null; // 预加载的视频元素
  #container = null; // 视频容器
  
  // 公共字段
  index = 0;       // 当前视频索引
  currentVideo = null; // 当前播放视频
  currentTime = 0; // 当前播放时间,可以指定视频初始化的时间

  constructor(videoNames, videoId, index = 0, currentTime = 0) {
    this.#videoNames = videoNames;
    this.index = index;
    this.currentTime = currentTime;
    this.#container = document.getElementById(videoId);
    this.#preloadNextVideo(); // 初始化预加载
  }
  
  // 预加载下一个视频(私有方法)
  #preloadNextVideo() {
    if (this.#nextVideo) return;
    
    this.#nextVideo = document.createElement('video');
    this.#nextVideo.src = `./video/${this.#videoNames[this.index]}`;
    this.#nextVideo.preload = 'auto';
    this.#nextVideo.muted = true;
    this.#nextVideo.style.display = 'none';
    
    // 保持播放进度
    this.#nextVideo.currentTime = this.currentTime;
    this.currentTime = 0; // 重置进度
    
    this.#container.appendChild(this.#nextVideo);

    this.#nextVideo.oncanplaythrough = () => {
      console.log('视频预加载完成:', this.#videoNames[this.index]);
    };
  }

  // 执行视频切换
  getVideo() {
    if (!this.#nextVideo) {
      this.#preloadNextVideo();
      return;
    }

    // 显示新视频并播放
    this.#nextVideo.style.display = 'block';
    this.#nextVideo.autoplay = true;
    this.#nextVideo.play();

    // 移除旧视频(带淡出效果)
    if (this.currentVideo) {
      this.currentVideo.style.opacity = '0';
      this.#container.removeChild(this.currentVideo);
    }

    // 更新状态
    this.currentVideo = this.#nextVideo;
    this.index = (this.index + 1) % this.#videoNames.length;
    this.#nextVideo = null;
    
    // 预加载下一个视频
    this.#preloadNextVideo();
  }
}

三、关键技术创新点

1. 双缓冲预加载机制

// 始终保持两个视频元素:
// - currentVideo: 当前播放
// - #nextVideo: 预加载的下一个

2. 播放进度保持

// 切换时保存当前时间
this.#nextVideo.currentTime = this.currentTime;

// 播放新视频后重置
this.currentTime = 0;

四、完整使用示例

// 1. 初始化
const switcher = new SwitchVideo(
  ['video1.mp4', 'video2.mp4', 'video3.mp4'],
  'video-container',
  0, // 初始索引
  10 // 初始播放时间(秒)
);
//上来就调用一次,保证初始化时有视频播放
  switcher.getVideo();

// 2. 添加控制按钮
document.getElementById('next-btn').addEventListener('click', () => {
  switcher.getVideo();
});