使用 XGPlayer 和 React 实现视频封面预览及播放功能
在现代 web 开发中,如何高效地实现视频的封面展示和播放是一项常见的需求。今天,我们将介绍如何利用 XGPlayer 和 React 实现一个带有封面图预览和点击播放功能的视频组件。
项目背景
在这个项目中,我们的目标是:
- 从视频中提取第一帧作为封面图。
- 实现点击封面图时播放视频,并展示视频播放器。
- 使用字节跳动的开源视频播放器 XGPlayer,并结合 React 来封装组件。
项目结构
我们将创建一个 VideoMessage
组件,它接受 extra
和 data
两个属性,其中 extra
包含了视频信息,比如视频的封面图和视频的 URL。
1. 初始化依赖
首先,我们需要安装以下依赖:
npm install xgplayer antd @ant-design/icons
- xgplayer:字节跳动提供的高效视频播放器。
- antd:UI 组件库,提供模态框和图标。
- @ant-design/icons:Ant Design 的图标库,用于展示播放和关闭图标。
2. 组件结构和功能实现
接下来,我们开始实现组件。
2.1 组件定义
import React, { useState, useEffect, useRef } from 'react';
import 'xgplayer/dist/index.min.css';
import { Image, Modal } from 'antd';
import { PlayCircleOutlined, CloseOutlined } from '@ant-design/icons';
import { getImageInfo } from '@/utils/functions'; // 用于获取图片大小的工具
import Player from 'xgplayer'; // 引入 XGPlayer
const VideoMessage = ({ extra, data }) => {
const [openVideo, setOpenVideo] = useState(false);
const [cover, setCover] = useState(extra.cover || ''); // 默认封面为空
const videoRef = useRef(null); // 用于隐藏的 video 元素
const playerRef = useRef(null); // 用于存储 XGPlayer 实例
// 获取图片尺寸信息
const img = (src, width = 200) => {
const info = getImageInfo(src);
if (info.width === 0 || info.height === 0) return {};
if (info.height > 300) return { height: '300px' };
if (info.width < width) {
return { width: `${info.width}px`, height: `${info.height}px` };
}
return { width: `${width}px`, height: `${info.height / (info.width / width)}px` };
};
// 播放视频
const onPlay = () => {
setOpenVideo(true); // 打开视频播放的 Modal
};
// 获取视频的第一帧作为封面图
const captureFirstFrame = (videoElement) => {
if (!videoElement) return;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置 canvas 尺寸为视频的尺寸
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
// 将视频帧绘制到 canvas 上
ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
// 将 canvas 转为 Blob 并设置为封面图
canvas.toBlob(function (blob) {
if (blob) {
const url = URL.createObjectURL(blob);
setCover(url); // 更新封面为第一帧图像
} else {
console.error("Failed to generate the blob from the canvas.");
}
}, 'image/jpeg', 0.8);
};
// 加载视频并提取第一帧
useEffect(() => {
const videoElement = videoRef.current;
if (videoElement) {
videoElement.src = "http://" + extra.url;
videoElement.crossOrigin = 'anonymous'; // 跨域设置,保证视频的加载
videoElement.currentTime = 1; // 直接跳到第一帧
videoElement.addEventListener('loadeddata', () => {
captureFirstFrame(videoElement); // 提取第一帧
});
return () => {
videoElement.removeEventListener('loadeddata', captureFirstFrame); // 清理事件
};
}
}, [extra.url]);
// 在打开视频时初始化播放器
useEffect(() => {
if (openVideo && extra.url) {
const player = new Player({
id: 'im-xgplayer',
url: "http://" + extra.url,
fluid: true, // 播放器自适应尺寸
autoplay: true, // 自动播放
lang: 'zh-cn',
});
playerRef.current = player;
// 关闭时销毁播放器实例
return () => {
if (playerRef.current) {
playerRef.current.destroy();
}
};
}
}, [openVideo, extra.url]);
return (
<>
<div
className="p-1 relative max-w-96"
onClick={onPlay}>
<Image
style={{ maxHeight: '100%', maxWidth: '100%' }}
src={cover} // 显示封面
preview={false}
/>
<div className="absolute top-1/2 left-1/2 w-8 h-8 cursor-pointer transform translate-x-[-50%] translate-y-[-50%]">
<PlayCircleOutlined
className="text-gray-800 dark:text-gray-200 hover:text-sky-500 dark:hover:text-sky-500"
style={{ fontSize: '36px' }}
/>
</div>
</div>
<video ref={videoRef} style={{ display: 'none' }} /> {/* 隐藏的 video 元素 */}
<Modal
open={openVideo}
onCancel={() => setOpenVideo(false)} // 关闭视频时关闭 Modal
footer={null}
width={800}
closeIcon={<CloseOutlined />}
>
<div id="im-xgplayer"></div> {/* 放置 XGPlayer 的容器 */}
</Modal>
</>
);
};
export default VideoMessage;
3. 功能详解
3.1 获取封面图
视频的封面图是通过 canvas 获取的。通过 canvas.toBlob
方法,我们能够将视频的第一帧转为图像 URL,从而设置为封面。
3.2 播放器初始化与销毁
当用户点击封面图时,打开一个模态框 (Modal
),并在该模态框内初始化 XGPlayer 播放器。每当视频加载并准备播放时,我们会通过 Player
类初始化播放器实例,autoplay
设置为 true
来自动播放。
3.3 动态更新封面
每当视频加载完成并播放时,我们会更新封面图,并通过 setCover
将第一帧设为视频的封面图。
3.4 样式和布局
使用了 Ant Design 的 Image 组件来显示封面图,同时使用 PlayCircleOutlined 图标作为播放按钮,点击时打开模态框,展示视频播放器。
4. 关键点总结
- Canvas API:利用 canvas 获取视频的第一帧并将其作为封面。
- XGPlayer:通过字节跳动提供的高性能播放器组件来播放视频。
- Ant Design Modal:封装视频播放器,点击封面时弹出播放窗口。
- React Hooks:使用
useState
和useEffect
进行状态管理和副作用处理。
5. 总结
通过结合 XGPlayer 和 React,我们能够实现一个流畅且功能丰富的视频播放器组件,支持从视频提取封面、点击播放并展示播放器等功能。这样的视频播放体验提升了应用的交互性和用户体验,同时也能有效利用视频播放器的强大功能。
6.效果展示