更新记录
2.0.1(2026-06-16)
增加使用说明
2.0.0(2026-06-16)
0.0.1
平台兼容性
uni-app(5.13)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | √ | √ | √ | √ | √ | √ | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
uni-app x(5.13)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
custom-video-player —— 跨平台原生视频播放插件
一款开箱即用的视频播放器组件,各平台底层走原生播放器,自带完整 UI 控件、手势交互,完整支持 0.5x ~ 2.0x 倍速播放。
适用于:教培视频、短视频 Feed、课程播放、直播回放等场景。
〇、运行要求(重要!)
由于本插件使用了 UTS 原生 SDK 调用各平台底层播放器(Android MediaPlayer、iOS AVPlayer 等),不同平台的运行方式不同:
| 运行平台 | 是否需要自定义基座 | 说明 |
|---|---|---|
| Web (H5) | 不需要 | 直接 运行 → 运行到浏览器 即可,底层用 HTML5 video |
| 微信小程序 | 不需要 | 直接 运行 → 运行到小程序模拟器,底层用微信 video 组件 |
| Android 真机/模拟器 | 需要 | 需先 运行 → 制作自定义基座,再用自定义基座运行 |
| iOS 真机/模拟器 | 需要 | 需先 运行 → 制作自定义基座,再用自定义基座运行 |
| 鸿蒙真机/模拟器 | 需要 | 需先制作自定义基座运行 |
如何制作自定义基座?
- HBuilderX 菜单 → 运行 → 运行到手机或模拟器 → 制作自定义基座
- 选择目标平台(Android / iOS),等待打包完成
- 打包完成后,再次 运行 → 运行到手机或模拟器,选择刚刚制作的自定义基座即可
小白提示:如果你是第一次开发,建议先在 Web(浏览器) 上调试,无需任何配置,效果和真机一致。等逻辑调通后再打自定义基座跑真机。
一、快速上手(1 分钟)
1. 导入组件
<template>
<custom-video-player
ref="playerRef"
src="https://www.w3schools.com/html/mov_bbb.mp4"
:autoplay="true"
:show-mute-btn="true"
@timeupdate=""
/>
</template>
<script lang="uts" setup>
import CustomVideoPlayer from '@/uni_modules/custom-video-player/components/custom-video-player/custom-video-player.uvue'
const playerRef = ref<any>(null)
function (e: { currentTime: number; duration: number }) {
console.log('进度:', e.currentTime.toFixed(1), '/', e.duration.toFixed(1))
}
</script>
这就行了——组件自动处理:原生播放器创建、控件渲染、手势交互、全屏切换、倍速菜单。你只需传入 src 即可播放。
2. 通过 ref 控制播放
// 播放 / 暂停
playerRef.value.play()
playerRef.value.pause()
// 跳转到第 30 秒
playerRef.value.seek(30)
// 切换到 1.5 倍速
playerRef.value.setRate(1.5)
// 进入全屏
playerRef.value.requestFullScreen()
// 读取当前状态
const state = playerRef.value.getState()
console.log(state.currentTime, state.duration, state.isPlaying)
二、运行 Demo
项目内置了完整的调试 Demo 页面,推荐先跑起来看看效果:
页面路径:pages/VideoSub/videoPlayerDemo
或在 pages.json 中跳转:
{ "path": "pages/VideoSub/videoPlayerDemo" }
Demo 提供:
- 多视频源切换
- 所有 Props 实时开关
- 手势操作演示
- 全事件日志输出
三、Props(组件属性)
基础属性
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
src |
String | '' |
视频地址(支持 http/https/本地路径) |
poster |
String | '' |
封面图地址,播放前显示 |
autoplay |
Boolean | false |
是否自动播放 |
loop |
Boolean | false |
是否循环播放 |
muted |
Boolean | false |
是否静音 |
object-fit |
String | 'contain' |
视频填充模式:contain / cover / fill |
initial-time |
Number | 0 |
初始播放位置(秒),即 start-seconds |
defaultRate |
Number | 1.0 |
默认倍速(0.5 / 1.0 / 1.25 / 1.5 / 2.0) |
duration |
Number | 0 |
预设时长(秒),视频加载后自动覆盖 |
video-id |
String | 自动生成 | 播放器唯一 ID,用于多实例区分 |
控件显隐
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
show-controls |
Boolean | true |
是否显示底部控制栏 |
show-play-btn |
Boolean | true |
是否显示底部播放/暂停按钮 |
show-center-play-btn |
Boolean | true |
是否显示中间大播放按钮 |
show-mute-btn |
Boolean | false |
是否显示静音按钮 |
show-fullscreen-btn |
Boolean | true |
是否显示全屏按钮(同 show-fullscreen) |
show-rate-btn |
Boolean | true |
是否显示倍速按钮 |
show-back-btn |
Boolean | true |
是否显示顶部返回按钮 |
show-more-btn |
Boolean | false |
是否显示顶部更多按钮 |
手势控制
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
enable-play-gesture |
Boolean | true |
双击播放/暂停 |
enable-progress-gesture |
Boolean | true |
水平滑动快进/快退 |
其他
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
String | '' |
顶部标题文字 |
tablet |
Boolean | false |
是否启用平板/宽屏适配(UI 等比放大) |
controls |
Boolean | true |
保留字段,对齐 uni-app video 组件 |
使用示例
<custom-video-player
src="https://example.com/video.mp4"
poster="https://example.com/cover.jpg"
:autoplay="true"
:loop="false"
:muted="false"
:default-rate="1.0"
object-fit="contain"
title="我的视频"
:show-mute-btn="true"
:show-back-btn="true"
:enable-progress-gesture="true"
:enable-play-gesture="true"
/>
四、Events(事件)
所有事件名对齐 uni-app / 微信小程序 VideoContext,可直接迁移。
| 事件 | 触发时机 | 回调参数 |
|---|---|---|
@ready |
播放器准备完成 | 无 |
@play |
开始/继续播放 | 无 |
@pause |
暂停播放 | 无 |
@ended |
播放结束 | 无 |
@state |
状态变化 | { state: string } |
@timeupdate |
播放进度变化 | { currentTime: number, duration: number } |
@load |
元数据加载完成 | { width: number, height: number, duration: number } |
@fullscreen |
全屏切换 | { fullScreen: boolean, direction: 'vertical'\|'horizontal' } |
@error |
播放失败 | { errMsg: string } |
@back |
点击顶部返回按钮 | 无 |
@ratechange |
倍速变更 | { rate: number } |
@buffering |
缓冲状态变化 | { isBuffering: boolean } |
state 取值说明
| 值 | 含义 |
|---|---|
idle |
初始状态,尚未准备 |
prepared |
准备完成,可以播放 |
playing |
正在播放 |
paused |
已暂停 |
stopped |
已停止(需重新 prepare 才能再播) |
finished |
播放完成(自然结束) |
error |
播放错误 |
使用示例
<custom-video-player
src="..."
@ready="onReady"
@play="onPlay"
@pause="onPause"
@timeupdate=""
@state="onState"
@load="onLoad"
@error="onError"
@back="onBack"
@ratechange=""
@buffering="onBuffering"
@fullscreen="onFullscreen"
/>
function onReady() { console.log('可以播放了') }
function onPlay() { console.log('开始播放') }
function onPause() { console.log('暂停了') }
function (e: { currentTime: number; duration: number }) {
// 更新进度条
progress.value = (e.currentTime / e.duration) * 100
}
function onLoad(e: { width: number; height: number; duration: number }) {
console.log(`视频尺寸 ${e.width}x${e.height},时长 ${e.duration}s`)
}
function onError(e: { errMsg: string }) {
uni.showToast({ title: '播放失败: ' + e.errMsg, icon: 'none' })
}
function onBack() {
// 自定义返回逻辑;返回按钮也可通过 show-back-btn="false" 隐藏
uni.navigateBack()
}
五、Ref API(通过 ref 调用组件方法)
组件暴露了完整的方法供外部控制:
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
play() |
— | void | 播放 |
pause() |
— | void | 暂停 |
stop() |
— | void | 停止(回到开头) |
seek(seconds) |
number |
void | 跳转到指定秒数 |
setRate(rate) |
number |
void | 设置倍速(0.5~2.0) |
playbackRate(rate) |
number |
void | 同 setRate(对齐 VideoContext) |
requestFullScreen(direction?) |
number? |
void | 进入全屏(0=竖屏 90=横屏) |
exitFullScreen() |
— | void | 退出全屏 |
enterFullscreen() |
— | void | 同 requestFullScreen(0) |
exitFullscreen() |
— | void | 同 exitFullScreen() |
togglePiP() |
— | void | 画中画开关(APP-Android) |
toggleBackgroundAudio() |
— | void | 后台音频/锁屏控制开关 |
getState() |
— | object |
获取播放器状态快照 |
getState() 返回值
{
currentTime: number // 当前播放秒数
duration: number // 总时长
rate: number // 当前倍速
isPlaying: boolean // 是否正在播放
isFullscreen: boolean // 是否全屏
isPiP: boolean // 是否画中画
videoWidth: number // 视频宽度(暂未实现)
videoHeight: number // 视频高度(暂未实现)
}
使用示例
const playerRef = ref<any>(null)
// 播放控制
playerRef.value.play()
playerRef.value.pause()
playerRef.value.seek(60) // 跳到 1 分钟
// 倍速切换
playerRef.value.setRate(2.0) // 2 倍速
// 全屏
playerRef.value.requestFullScreen(90) // 横屏全屏
// 画中画(Android)
playerRef.value.togglePiP()
// 读取进度
const state = playerRef.value.getState()
console.log(`${state.currentTime}/${state.duration}`)
六、手势交互
组件内置以下手势,无需额外代码:
| 手势 | 操作 | 效果 |
|---|---|---|
| 双击 | 在视频画面上快速双击 | 播放 / 暂停 |
| 水平滑动 | 在视频画面上左右滑动 | 快进 / 快退(每 50px ≈ 10 秒) |
| 单击 | 在视频画面上单击 | 显示 / 隐藏控件(3 秒自动隐藏) |
| 点击进度条 | 点击/拖拽底部进度条 | seek 到指定位置 |
手势可通过 Props 关闭:
<custom-video-player
:enable-play-gesture="false" <!-- 关闭双击 -->
:enable-progress-gesture="false" <!-- 关闭水平滑动 -->
/>
七、控件自动隐藏
播放时,底部控制栏和顶部标题栏会在 3 秒无操作后自动隐藏,触摸视频画面即可重新显示。
- 暂停状态下控件始终显示
- 视频未开始播放时控件始终显示
- 触摸视频画面可以随时唤醒控件
八、完整使用示例
一个包含常用功能的完整示例:
<template>
<view style="flex:1">
<custom-video-player
ref="playerRef"
:src="videoUrl"
:poster="posterUrl"
:title="videoTitle"
:autoplay="false"
:default-rate="1.0"
object-fit="contain"
:show-mute-btn="true"
:show-back-btn="true"
:enable-play-gesture="true"
:enable-progress-gesture="true"
@ready="onReady"
@play="onPlay"
@pause="onPause"
@timeupdate=""
@error="onError"
@back="onBack"
/>
</view>
</template>
<script lang="uts" setup>
import CustomVideoPlayer from '@/uni_modules/custom-video-player/components/custom-video-player/custom-video-player.uvue'
const playerRef = ref<any>(null)
const videoUrl = ref('https://www.w3schools.com/html/mov_bbb.mp4')
const posterUrl = ref('')
const videoTitle = ref('示例视频')
function onReady() {
console.log('播放器就绪')
}
function onPlay() {
console.log('正在播放')
}
function onPause() {
console.log('已暂停')
}
function (e: { currentTime: number; duration: number }) {
// 业务逻辑,比如记录学习进度
const progress = e.duration > 0 ? (e.currentTime / e.duration) * 100 : 0
console.log('进度:', progress.toFixed(1) + '%')
}
function onError(e: { errMsg: string }) {
uni.showToast({ title: '播放失败', icon: 'none' })
}
function onBack() {
uni.navigateBack()
}
</script>
九、目录结构
uni_modules/custom-video-player/
├── package.json
├── readme.md ← 你正在看的文档
├── utssdk/
│ ├── interface.uts # 统一接口定义(类型 + API 契约)
│ ├── app-android/index.uts # Android: MediaPlayer + SurfaceView
│ ├── app-ios/index.uts # iOS: AVPlayer + AVPlayerLayer
│ ├── app-harmony/index.uts # 鸿蒙: AVPlayer + XComponent
│ ├── web/index.uts # Web: HTML5 video
│ └── mp-weixin/index.uts # 微信小程序: video 组件
└── components/
└── custom-video-player/
└── custom-video-player.uvue # 统一组件层(跨平台 UI)
十、各平台原生实现
| 平台 | 原生播放器 | 倍速 API | 支持档位 |
|---|---|---|---|
| Android | MediaPlayer + SurfaceView | setPlaybackParams(speed) |
0.5x ~ 2.0x |
| iOS | AVPlayer + AVPlayerLayer | AVPlayer.rate |
0.5x ~ 2.0x |
| 鸿蒙 | AVPlayer + XComponent | AVPlayer.speed |
0.5x ~ 2.0x |
| Web (H5) | HTML5 video | video.playbackRate |
0.25x ~ 4.0x |
| 微信小程序 | video 组件 + VideoContext | VideoContext.playbackRate() |
0.5x ~ 2.0x |
十一、注意事项
1. 视频源要求
- 推荐使用 HTTPS 地址
- 支持格式:MP4、M3U8(各平台兼容性有差异)
- 本地路径请使用
@/static/xxx.mp4或/static/xxx.mp4
2. 倍速生效时机
| 平台 | 生效时机 |
|---|---|
| Android | 播放状态 (state == 'playing') |
| iOS | 播放状态 (state == 'playing') |
| 鸿蒙 | 播放状态 (state == 'playing') |
| Web | 任何时候 |
| 微信小程序 | 任何时候 |
建议: 先调用 play(),再调用 setRate(),确保倍速在各平台生效。
3. Android API 版本
MediaPlayer.setPlaybackParams()需要 API 23+(Android 6.0)- 低版本设备不支持倍速,会降级为正常速度
4. 直播场景
- 直播流(如 M3U8)不设置
duration,进度条会自动适配 - 微信小程序端 M3U8 需基础库版本 ≥ 2.0.0
5. 多实例
同一页面可放多个 <custom-video-player>,通过 video-id 区分:
<custom-video-player video-id="player1" src="..." />
<custom-video-player video-id="player2" src="..." />
不传 video-id 时组件自动生成唯一 ID。
6. 画中画 / 后台音频
togglePiP()目前仅在 Android 平台有原生实现toggleBackgroundAudio()用于启用锁屏信息 + 后台音频播放(Android/iOS)- 其他平台调用这些方法不会崩溃,只是无效果
十二、常见问题
Q: 如何隐藏所有控件,只显示视频画面?
<custom-video-player
:show-controls="false"
:show-center-play-btn="false"
:enable-play-gesture="false"
:enable-progress-gesture="false"
/>
Q: 如何获取当前播放进度?
两种方式:
- 监听
@timeupdate事件 - 主动调用
playerRef.value.getState().currentTime
Q: 视频加载失败怎么处理?
监听 @error 事件,组件会自动显示"播放失败,点击重试"的 UI。
Q: 如何在微信小程序中使用?
直接引入组件即可——底层自动切换为微信 <video> 组件 + VideoContext,无需额外配置。
Q: 如何自定义倍速列表?
目前固定为 0.5x / 1.0x / 1.25x / 1.5x / 2.0x。如需自定义,可修改组件中 availableRates 常量:custom-video-player.uvue 第 148 行。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 0
赞赏 0
下载 12267886
赞赏 1922
赞赏
京公网安备:11010802035340号