React 框架使用说明
ZWPlayer 提供了针对 React 框架的专用接口包 zwplayer-react,支持 React 16.8+、17.x、18.x 和 19.x 版本。
1. 安装步骤
1.1 安装接口包
npm i zwplayer-react --save
1.2 验证安装
安装成功后,项目的 public 目录下会自动生成 zwplayer 核心库目录,该目录必须随项目一起构建发布。
1.3 版本要求
- React 16.8+(需要 Hooks 支持)
- 支持 Create React App、Vite、Next.js 等构建工具
2. 组件使用
2.1 基本使用示例
import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';
function VideoPlayer() {
const playerRef = useRef(null);
const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';
const handlePlayerReady = () => {
console.log('Player ready event.');
const player = playerRef.current;
// 播放器就绪后可以调用方法
};
const handlePlayerMediaEvent = (event) => {
console.log('media event:', event.type);
};
return (
<div className="player-container">
<ZwPlayer
ref={playerRef}
nodeid="main-player"
murl={movieUrl}
onready={handlePlayerReady}
onmediaevent={handlePlayerMediaEvent}
autoplay={false}
snapshotButton={true}
optionButton={true}
infoButton={true}
enableDanmu={true}
chapterButton={true}
fluid={true}
disableMutedConfirm={true}
/>
</div>
);
}
export default VideoPlayer;
2.2 弹幕功能示例
import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';
function DanmuPlayer() {
const playerRef = useRef(null);
const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';
const handlePlayerReady = () => {
console.log('Player ready event.');
const player = playerRef.current;
// 添加测试弹幕
setTimeout(() => {
if (player && player.appendDanmu) {
player.appendDanmu({
border: '1px solid #ccc',
text: '欢迎来到 ZWPlayer 弹幕演示!',
color: '#ff6b6b'
});
}
}, 3000);
};
const handleSendDanmu = (danmuText) => {
if (!danmuText) return;
const player = playerRef.current;
let danmu;
try {
const jtext = JSON.parse(danmuText);
danmu = {
border: '1px solid #ccc',
text: jtext['text']
};
} catch (e) {
danmu = {
border: '1px solid #ccc',
text: danmuText
};
}
if (player && player.appendDanmu) {
player.appendDanmu(danmu);
}
};
return (
<div>
<ZwPlayer
ref={playerRef}
murl={movieUrl}
onready={handlePlayerReady}
autoplay={false}
sendDanmu={handleSendDanmu}
enableDanmu={true}
danmuBarId="danmu-controlbar"
disableMutedConfirm={true}
fluid={true}
/>
<div id="danmu-controlbar" className="danmubar"></div>
</div>
);
}
export default DanmuPlayer;
弹幕控制栏样式:
.danmubar {
height: 50px;
background-color: #232323;
padding: 8px;
box-sizing: border-box;
display: flex;
}
.danmubar .zwp_danmu-controlbar {
width: 60%;
}
2.3 Logo 水印示例
import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';
function LogoPlayer() {
const playerRef = useRef(null);
const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';
const poster = 'https://cdn.zwplayer.cn/media/b44c43c90be3521bc352aad1e80f9cd0_thumb.jpg';
const logoConfig = {
icon: 'https://cdn.zwplayer.cn/logo.png',
dock: 'right', // 位置:left, right
x: '5%', // 水平偏移
y: '5%', // 垂直偏移
width: '10%', // 宽度
height: '10%', // 高度
opacity: 70 // 透明度 0-100
};
return (
<ZwPlayer
ref={playerRef}
murl={movieUrl}
logo={logoConfig}
poster={poster}
autoplay={false}
disableMutedConfirm={true}
fluid={true}
/>
);
}
export default LogoPlayer;
2.4 缩略图示例
import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';
function ThumbnailPlayer() {
const playerRef = useRef(null);
const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';
const thumbnails = {
url: 'https://cdn.zwplayer.cn/media/b44c43c90be3521bc352aad1e80f9cd0_thumb.jpg',
width: 160,
height: 90,
row: 9,
col: 9,
total: 74
};
return (
<ZwPlayer
ref={playerRef}
murl={movieUrl}
thumbnails={thumbnails}
fluid={true}
/>
);
}
export default ThumbnailPlayer;
2.5 章节分段示例
import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';
function ChapterPlayer() {
const playerRef = useRef(null);
const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';
const handlePlayerReady = () => {
const player = playerRef.current;
const chapters = [
{
title: "分段1",
desc: "分段1描述",
time: 0,
duration: 50,
thumb: null
},
{
title: "分段2",
desc: "分段2描述",
time: 50,
duration: 100,
style: { background: "blue" },
image: null
},
{
title: "分段3",
desc: "分段3描述",
time: 100,
duration: 200,
style: { background: "green" },
image: null
}
];
if (player) {
player.setChapters(chapters);
}
};
return (
<ZwPlayer
ref={playerRef}
murl={movieUrl}
onready={handlePlayerReady}
chapterButton={true}
fluid={true}
/>
);
}
export default ChapterPlayer;
2.6 路由切换(配合 React Router)
zwplayer-react 内置了对 react-router-dom 的支持。当安装了 react-router-dom 时,组件会自动监听路由变化并在路由切换前安全清理播放器资源,防止 DOM 访问错误。
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ZwPlayer } from 'zwplayer-react';
function VideoPage() {
const playerRef = useRef(null);
return (
<ZwPlayer
ref={playerRef}
murl="https://cdn.zwplayer.cn/media/video.mp4"
fluid={true}
/>
);
}
// 路由切换时播放器会自动安全销毁
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/video" element={<VideoPage />} />
<Route path="/other" element={<div>Other Page</div>} />
</Routes>
</BrowserRouter>
);
}
注意:react-router-dom 是可选依赖,未安装时不会影响播放器的正常使用。
3. 变动属性
ZwPlayer 组件的属性与原生 zwplayer 构造函数参数对象的属性大部分相同,但 zwplayer-react 对部分属性做了调整:
| 属性名称 | 说明 | 备注 |
|---|---|---|
| murl | 媒体地址参数(可以是 string、object、array 类型)。如果此属性在运行中发生变动,则组件会自动调用 play 方法打开新的地址。通过修改绑定的 state 变量,可以动态切换播放节目。 |
作用改动 |
| nodeid | 用于 ZwPlayer 组件顶级父节点 div 的 id,如果不提供,组件会自动生成一个。 |
新增 |
| zwplayerlib | zwplayer 库地址。zwplayer-react 底层采用动态加载原生 zwplayer 库的方式,不会随 React 的 build 命令将 zwplayer 底层库编译进项目。这样可以在项目编译发布后直接替换 zwplayer 库文件实现无缝升级。此参数可以缺省,缺省时使用 public 目录下的 zwplayer/zwplayer.js 路径。 |
新增 |
| danmuBarId | 用于定位 zwplayer 弹幕输入控制条的 div 元素的 id。提供此参数可以避免调用 buildDanmuControlbar 函数来创建弹幕控制条。控制条的 class 名为 zwp_danmu-controlbar,可以使用该 class 名控制弹幕控制条的风格。 |
新增 |
| style | 应用到播放器容器 div 上的内联样式对象。 | 新增 |
| videoprop | 视频元素属性对象,可以包含 url 和 videostyle 属性。 |
新增 |
| onready | 播放器初始化完成回调函数,参数为播放器实例。 | 事件属性 |
| onmediaevent | 媒体事件回调函数,参数为 event 对象。 | 事件属性 |
| onneterror | 网络错误回调函数。 | 事件属性 |
| onnetclose | 网络关闭回调函数。 | 事件属性 |
| onFileSelected | 文件选择回调函数。 | 事件属性 |
| onFileLoaded | 文件加载完成回调函数。 | 事件属性 |
| 其它 | 请参见 zwplayer 播放器构造函数的参数说明。 |
常用属性说明
显示控制相关:
autoplay: 是否自动播放(boolean,默认false)fluid: 是否启用流体布局(boolean,默认false)snapshotButton: 是否显示截图按钮(boolean)optionButton: 是否显示选项按钮(boolean)infoButton: 是否显示信息按钮(boolean)chapterButton: 是否显示章节菜单按钮(boolean)enableDanmu: 是否启用弹幕功能(boolean)
媒体相关:
murl: 媒体地址(string、object或array)poster: 封面图地址(string)thumbnails: 缩略图配置(object)
功能相关:
sendDanmu: 弹幕发送回调函数(function)disableMutedConfirm: 是否禁用静音确认(boolean)keepAudioWindow: 是否保持音频窗口(boolean)localPlayback: 是否本地播放(boolean)recordButton: 是否显示录制按钮(boolean)segmentButton: 是否显示分段按钮(boolean)
4. 方法调用
ZwPlayer 组件通过 React 的 forwardRef + useImperativeHandle 暴露播放器方法。使用 useRef 获取组件引用后即可调用。
4.1 获取播放器实例
import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';
function VideoPlayer() {
const playerRef = useRef(null);
const handlePlayerReady = () => {
const player = playerRef.current;
console.log('播放器实例:', player);
};
return (
<ZwPlayer
ref={playerRef}
murl="video.mp4"
onready={handlePlayerReady}
/>
);
}
4.2 常用方法
// 播放/暂停/恢复
playerRef.current.play();
playerRef.current.pause();
playerRef.current.resume();
playerRef.current.stop();
// 跳转到指定时间(秒)
playerRef.current.seekTime(30);
// 添加弹幕
playerRef.current.appendDanmu({
border: '1px solid #ccc',
text: '这是一条弹幕',
color: '#ff6b6b'
});
// 设置章节
playerRef.current.setChapters([{
title: "分段1",
desc: "分段1描述",
time: 0,
duration: 50
}]);
// 获取当前播放时间
const currentTime = playerRef.current.getCurrentTime();
// 获取视频总时长
const duration = playerRef.current.getDuration();
// 音量与静音
playerRef.current.setMute(true);
// 全屏
playerRef.current.setullscr(true);
// 字幕
playerRef.current.addSubtitle('https://example.com/subtitle.vtt', 0, '中文');
playerRef.current.removeSubtitle();
// 弹幕控制
playerRef.current.setEnableDanmu(true);
// 弹幕控制栏
playerRef.current.buildDanmuControlbar('danmu-bar-id', 'custom-class');
// 通知尺寸变化
playerRef.current.notifyResize(800, 450);
// 灯光控制
playerRef.current.lightOff();
playerRef.current.lightOn();
// 获取原始播放器实例(高级用法)
const rawPlayer = playerRef.current.player;
// 销毁播放器
playerRef.current.destroy();
5. StrictMode 兼容性
React 18 的 StrictMode 会在开发模式下触发两次 useEffect,可能导致播放器重复创建。zwplayer-react 内置了实例缓存机制来处理此问题:
- 使用
window.__zwplayer_instances__全局 Map 跟踪播放器实例 - 当检测到重复创建时自动复用已有实例
- 组件卸载时安全清理所有资源(定时器、ResizeObserver、DOM 引用等)
注意:此机制在生产模式下不会触发额外开销。
6. 示例仓库
- Gitee: https://gitee.com/chenfanyu/zwplayer-react-demo
- GitHub: https://github.com/chenfanyu/zwplayer-react-demo
7. 注意事项
7.1 项目配置
- 目录结构: 安装前确保项目存在
public目录 - 核心库:
public/zwplayer目录必须随项目一起发布 - 动态加载:
zwplayer采用动态加载机制,支持无缝升级,不会被打包进最终的 bundle - 方法调用: 通过
useRef引用调用播放器方法
7.2 最佳实践
-
使用条件渲染控制显示
{showPlayer && ( <ZwPlayer ref={playerRef} murl={movieUrl} fluid={true} /> )}使用条件渲染(
&&或三元运算符)而不是 CSS 隐藏,可以确保播放器正确初始化和销毁。 -
等待播放器就绪后再调用方法
const handlePlayerReady = () => { const player = playerRef.current; // 播放器就绪后才能调用方法 player.seekTime(30); }; -
动态切换视频
直接修改
murl的 state 值,组件会自动重新加载:const [videoUrl, setVideoUrl] = useState('video1.mp4'); // 切换视频 setVideoUrl('video2.mp4'); -
响应式布局
.player-container { width: 100%; max-width: 1280px; margin: 0 auto; } @media (max-width: 768px) { .player-container { width: 100%; height: auto; aspect-ratio: 16/9; } }
7.3 常见问题
Q: 为什么播放器无法显示?
A: 检查以下几点:
- 确保媒体 URL 可访问
- 检查浏览器控制台是否有错误信息
- 确认
public/zwplayer目录存在且包含必需的文件 - 确认使用
{showPlayer && <ZwPlayer ... />}而非 CSS 隐藏
Q: 如何动态切换视频?
A: 直接修改 murl 的 state 值:
const [videoUrl, setVideoUrl] = useState('video1.mp4');
setVideoUrl('new-video-url.mp4');
Q: StrictMode 下为什么会出现两个播放器?
A: 这是 React 18 StrictMode 的预期行为。zwplayer-react 内置了实例缓存机制来自动处理此问题,无需额外配置。
Q: 如何自定义弹幕控制栏样式?
A: 通过 CSS 类名直接控制:
.danmubar .zwp_danmu-controlbar {
width: 60%;
background-color: #232323;
}
Q: 如何获取播放器的当前状态?
A: 通过 useRef 获取组件引用后调用相应方法:
const player = playerRef.current;
const currentTime = player.getCurrentTime();
const duration = player.getDuration();
7.4 项目结构建议
Create React App 项目结构:
your-react-project/
├── public/
│ └── zwplayer/ # 播放器核心库(自动生成,必须发布)
├── src/
│ ├── components/
│ │ └── VideoPlayer.jsx # 播放器封装组件
│ ├── pages/
│ │ └── VideoPage.jsx # 使用播放器的页面
│ ├── App.jsx
│ └── index.js
├── package.json
└── vite.config.js (或 react-scripts)
7.5 调试建议
-
监听播放器就绪事件
const handlePlayerReady = () => { console.log('播放器已就绪:', playerRef.current); }; -
监听所有媒体事件
const handlePlayerMediaEvent = (event) => { console.log('媒体事件:', event.type, event); }; -
使用浏览器开发者工具
- 检查网络请求,确认
zwplayer.js正确加载 - 查看控制台是否有错误信息
- 使用元素检查器查看 DOM 结构
- 检查网络请求,确认
7.6 性能优化
- 延迟加载: 对于非首屏的播放器,使用条件渲染延迟加载
- 销毁实例: 组件卸载时播放器实例会被自动清理
- 资源预加载: 对于关键视频,可以考虑预加载
- CDN 加速: 将
zwplayer核心库部署到 CDN,使用zwplayerlib属性指定
8. 更新日志
- v1.0.5: 支持 React 19,新增路由安全切换
- v1.0.4: 新增缩略图、章节、弹幕等功能
- v1.0.2: 优化 StrictMode 兼容性
- v1.0.1: 初始版本,支持基本播放功能