@cqsjjb/web-video-player
v1.0.0
Published
基于 video.js 封装的 React 视频播放器组件,专为网络课程教育应用设计
Downloads
93
Maintainers
Readme
@cqsjjb/web-video-player
@cqsjjb/web-video-player 是一个基于 video.js 封装的 React 视频播放器组件,专为网络课程教育应用设计,提供丰富的视频播放功能和高度可定制的用户体验。
特性
- 多清晰度支持 - 支持多视频源切换,自动清晰度选择
- 智能进度条 - 自定义双层进度条,支持已观看/未观看区域限制
- 试看功能 - 内置试看时间限制,支持付费内容预览
- 水印支持 - 可自定义水印文本和样式
- 字幕轨道 - 支持多语言字幕和音轨切换
- 播放控制 - 丰富的播放控制选项(速率、画中画、全屏等)
- 权限控制 - 细粒度的功能控制(下载、快进、音量等)
- TypeScript 支持 - 完整的类型定义
安装
npm install @cqsjjb/web-video-player
# 或
yarn add @cqsjjb/web-video-player
# 或
pnpm add @cqsjjb/web-video-player🚀 快速开始
import React from 'react';
import WebVideoPlayer from '@cqsjjb/web-video-player';
function App() {
return (
<WebVideoPlayer
width="800"
sources={[
{ src: 'https://example.com/video.mp4', label: '高清', default: true }
]}
poster="https://example.com/poster.jpg"
/>
);
}API 文档
WebVideoPlayerProps
| 属性 | 类型 | 默认值 | 说明 |
|------|------|-------|------|
| width | number \| string | 520 | 播放器宽度,数字(px)或百分比 |
| sources | VideoSource[] | [] | 视频源列表,支持多清晰度切换 |
| poster | string | undefined | 视频封面图 URL |
| tracks | VideoTrack[] | [] | 字幕轨道列表 |
| fluid | boolean | true | 是否自适应父容器宽度 |
| preload | 'auto' \| 'metadata' \| 'none' | 'auto' | 视频预加载策略 |
| controls | boolean | true | 是否显示默认控制栏 |
| autoplay | boolean | false | 是否自动播放 |
| allowFullscreen | boolean | true | 是否允许全屏 |
| allowDownload | boolean | true | 是否显示下载按钮 |
| trialTime | number | undefined | 试看时长(秒),超过暂停并回到起始位置 |
| watermark | string | undefined | 视频水印文本 |
| watermarkStyle | WatermarkStyle | {} | 水印样式配置 |
| subtitleStyle | React.CSSProperties | undefined | 字幕容器样式,作用于 .vjs-text-track-display |
| subtitleClassName | string | undefined | 附加到 .vjs-text-track-display 的类名,便于自定义样式 |
| disableSeek | boolean | false | 是否禁用快进 |
| enablePiP | boolean | false | 是否启用画中画 |
| disableVolume | boolean | false | 是否隐藏音量控制 |
| seekableWatchedOnly | boolean | false | 是否仅允许在已观看区域拖动进度 |
| muted | boolean | false | 是否默认静音 |
| loop | boolean | false | 是否循环播放 |
| mini | boolean | false | 是否启用迷你模式(非全屏仅显示播放/暂停、全屏按钮) |
| rootStyle | React.CSSProperties | {} | 播放器根元素样式 |
| playbackRates | number[] | [] | 播放速率选项 |
| enablePlaybackRate | boolean | true | 是否启用播放速率控制 |
| showDuration | boolean | true | 是否显示时长信息 |
| onTrialEnded | () => void | undefined | 试看结束回调 |
| onError | (error?: any) => void | undefined | 播放错误回调 |
VideoSource
interface VideoSource {
/** 视频地址 */
src: string;
/** 显示名称,例如 "高清"、"标清" */
label: string;
/** 视频类型,如 "video/mp4",可选,会自动检测 */
type?: string;
/** 是否为默认播放源,默认 false */
default?: boolean;
}VideoTrack
interface VideoTrack extends React.TrackHTMLAttributes<HTMLTrackElement> {}WatermarkStyle
interface WatermarkStyle extends React.CSSProperties {
/** 水印位置,默认 'top-left' */
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
/** 水印透明度,默认 0.3 */
opacity?: number;
/** 水印字体大小,默认 14 */
fontSize?: number;
/** 水印颜色,默认 '#fff' */
color?: string;
}WebVideoPlayerRef
interface WebVideoPlayerRef {
/** 获取 video.js player 实例 */
getPlayer: () => videojs.Player | null;
/** 获取原生 HTMLVideoElement */
getNativePlayer: () => HTMLVideoElement | null;
}使用示例
基础用法
import React from 'react';
import WebVideoPlayer from '@cqsjjb/web-video-player';
function BasicExample() {
return (
<WebVideoPlayer
width="800"
sources={[
{ src: 'https://example.com/video.mp4', label: '高清', default: true }
]}
poster="https://example.com/poster.jpg"
/>
);
}多清晰度切换
import React, { useRef } from 'react';
import WebVideoPlayer, { WebVideoPlayerRef } from '@cqsjjb/web-video-player';
function MultiQualityExample() {
const playerRef = useRef<WebVideoPlayerRef>(null);
const handleGetPlayer = () => {
const player = playerRef.current?.getPlayer();
console.log('Player instance:', player);
};
return (
<div>
<WebVideoPlayer
ref={playerRef}
width="100%"
sources={[
{ src: 'https://example.com/video-480p.mp4', label: '480P', default: true },
{ src: 'https://example.com/video-720p.mp4', label: '720P' },
{ src: 'https://example.com/video-1080p.mp4', label: '1080P' }
]}
poster="https://example.com/poster.jpg"
playbackRates={[0.5, 1, 1.25, 1.5, 2]}
onError={(error) => console.error('播放错误:', error)}
/>
<button onClick={handleGetPlayer}>获取播放器实例</button>
</div>
);
}试看功能
import React, { useState } from 'react';
import WebVideoPlayer from '@cqsjjb/web-video-player';
function TrialExample() {
const [trialEnded, setTrialEnded] = useState(false);
const handleTrialEnded = () => {
setTrialEnded(true);
alert('试看结束,请购买完整版');
};
return (
<div>
{trialEnded && (
<div style={{ padding: '20px', background: '#f0f0f0', marginBottom: '10px' }}>
试看已结束,请购买完整版继续观看
</div>
)}
<WebVideoPlayer
width="800"
sources={[
{ src: 'https://example.com/premium-video.mp4', label: '高清', default: true }
]}
trialTime={60} // 60秒试看
watermark="试看版本"
watermarkStyle={{
position: 'bottom-right',
opacity: 0.5,
fontSize: 16,
color: '#ff0000'
}}
onTrialEnded={handleTrialEnded}
/>
</div>
);
}字幕支持
import React from 'react';
import WebVideoPlayer from '@cqsjjb/web-video-player';
function SubtitleExample() {
return (
<WebVideoPlayer
width="800"
sources={[
{ src: 'https://example.com/video.mp4', label: '高清', default: true }
]}
tracks={[
{
kind: 'subtitles',
src: 'https://example.com/subtitles-zh.vtt',
srcLang: 'zh',
label: '中文字幕',
default: true
},
{
kind: 'subtitles',
src: 'https://example.com/subtitles-en.vtt',
srcLang: 'en',
label: 'English'
}
]}
/>
);
}字幕样式控制
function SubtitleStyleExample() {
return (
<WebVideoPlayer
sources={[
{ src: 'https://example.com/video.mp4', label: '高清', default: true }
]}
tracks={[
{
kind: 'subtitles',
src: 'https://example.com/subtitles-zh.vtt',
srcLang: 'zh',
label: '中文字幕',
default: true
}
]}
subtitleStyle={{
color: '#fff',
textShadow: '0 0 4px rgba(0, 0, 0, 0.9)',
fontSize: '1.2rem',
backgroundColor: 'rgba(0, 0, 0, 0.35)',
padding: '4px 10px',
borderRadius: '6px'
}}
/>
);
}权限控制
import React from 'react';
import WebVideoPlayer from '@cqsjjb/web-video-player';
function PermissionControlExample() {
return (
<WebVideoPlayer
width="800"
sources={[
{ src: 'https://example.com/video.mp4', label: '高清', default: true }
]}
// 禁用下载和右键菜单
allowDownload={false}
// 禁用快进
disableSeek={true}
// 禁用音量控制
disableVolume={true}
// 只能在已观看区域快进
seekableWatchedOnly={true}
// 禁用画中画
enablePiP={false}
/>
);
}自定义样式
import React from 'react';
import WebVideoPlayer from '@cqsjjb/web-video-player';
function CustomStyleExample() {
return (
<WebVideoPlayer
width="100%"
sources={[
{ src: 'https://example.com/video.mp4', label: '高清', default: true }
]}
rootStyle={{
borderRadius: '8px',
overflow: 'hidden',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
}}
watermark="自定义水印"
watermarkStyle={{
position: 'bottom-left',
opacity: 0.3,
fontSize: 14,
color: '#ffffff',
textShadow: '1px 1px 2px rgba(0, 0, 0, 0.5)'
}}
/>
);
}最佳实践
1. 性能优化
// 使用 useMemo 优化 sources 数组
const sources = useMemo(() => [
{ src: videoUrl, label: '高清', default: true }
], [videoUrl]);
// 使用 useCallback 优化回调函数
const handleError = useCallback((error) => {
console.error('播放错误:', error);
}, []);2. 错误处理
const [error, setError] = useState(null);
<WebVideoPlayer
sources={sources}
onError={(err) => {
setError(err);
// 可以显示错误提示或重试按钮
}}
/>
{error && (
<div className="error-message">
视频加载失败,请检查网络连接
</div>
)}3. 响应式设计
// 使用 CSS 媒体查询或 JavaScript 动态调整
const [playerWidth, setPlayerWidth] = useState('100%');
useEffect(() => {
const updateWidth = () => {
if (window.innerWidth < 768) {
setPlayerWidth('100%');
} else {
setPlayerWidth('800px');
}
};
updateWidth();
window.addEventListener('resize', updateWidth);
return () => window.removeEventListener('resize', updateWidth);
}, []);License
MIT License - 详见 LICENSE 文件
版权信息
版权所有:重庆市建教帮科技有限责任公司
