更新记录
0.3.1(2026-09-29)
Added
- README 新增「注意事项」章节:蒸汽模式不支持 rpx、退出全屏字体变大、watch 不触发、@keyframes 不可用、Math.random() 返回 0、Element.animate() 不支持、iOS 事件对象兼容说明
Fixed
- iOS 自定义 UI 时间/状态不更新:
getEventValue 先尝试 (e as any)[key] 属性访问,失败再 fallback 到 (e as Map<string, any>).get(key)
- 所有 Demo 页面 rpx → px 转换(d-video/vapor/live),2rpx=1px
0.2.0(2026-09-29)
新增
- HLS 直播 Demo — 新增
pages/live/index 直播页面,支持 HLS/FLV 切换、断流重连提示
- switchSource API — 组件暴露
switchSource(url) 方法,Vapor 模式下直接调用切换视频源(不依赖 prop watch)
- 鸿蒙全屏横屏 — 鸿蒙端全屏通过
$setPageStyle('pageOrientation', 'landscape') 实现横屏切换
- H5 全屏 — 使用原生 DOM Fullscreen API(
el.requestFullscreen() / document.exitFullscreen())
- Iconfont 图标 — 控制栏全部替换为 iconfont 图标(播放/暂停/音量/静音/全屏/返回)
- README 文档 — 组件 API、Props、Events、Iconfont 用法、平台支持全覆盖
修复
- 视频源切换失效 — Vapor 模式下
watch(() => props.src) 不触发,改用暴露 switchSource(url) 方法直接调用
- 图标不显示 — 字体码点错误(U+EA24-31 → U+E612/E60F/E610/E611/E615/E617),改用字体实际包含的码点
- Iconfont 写法 — 模板中用 HTML 实体
 而非 JS 转义 '\uE612'
- 字体加载方式 — 从
uni.loadFontFace JS API 改为 CSS @font-face 全局加载,跨平台通用
- 声音图标反了 — 静音时显示静音图标,有声时显示音量图标
- EOF 位置不同步 — 播放结束时进度停在 01:29 而非 01:30,在
onNativeEvent EOF 分支补发 emitTimeupdate
- EOF loading 不消失 — 新增
nativeIsEof() 轮询 eof-reached 属性
- 总时长显示 00:00 — 模板改用
formatTime(durationMs / 1000)
- 播放按钮不切换 —
nativePlay/nativePause 设置 player.state
- H5 video 自带 UI — 添加
controls="false" 等属性隐藏原生控制栏
- 弹幕渲染 — Vapor 模式下重构为
v-for + setInterval 推进位置,替代不可用的 createElement
变更
- 控制栏布局 — 左侧播放/时间,右侧倍速/弹幕/音量/全屏,用
ctrl-left/ctrl-right 分组
- 移除清晰度按钮 — 控制栏不再显示清晰度按钮(API 保留)
- Demo 页面精简 — Vapor demo 去掉清晰度切换,新增直播跳转入口
平台兼容性
uni-app x(5.0)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
微信小程序 |
| √ |
√ |
8.0 |
16 |
√ |
- |
d-video · 蒸汽模式视频播放器
对齐官方 uni-video 架构,UI 直接写 view、native-view 桥接 libmpv 引擎,支持蒸汽(Vapor)模式与直播/倍速/弹幕/全屏。
特性
- 蒸汽模式 — 视图层直出 bytecode/nativecode,无 VDOM diff
- native-view 桥接 — Android 端通过
native-view 桥接 libmpv,Web 端回退内置 <video>
- 跨平台 — Android / iOS / 鸿蒙 / H5 四端覆盖
- 直播支持 — HLS/FLV/RTMP/RTSP/WebRTC 直播流,断流自动重连,直播模式自动隐藏进度条与倍速
- 弹幕引擎 — Vapor 视图层 v-for + setInterval 推进,不经过 VDOM diff
- 图标字体 — CSS
@font-face 全局加载,模板用 HTML 实体  引用
- 全屏 — Android 沉浸式 +
requestedOrientation,iOS/鸿蒙 $setPageStyle 横屏,H5 原生 DOM Fullscreen API
- 自定义 UI —
controls="false" 隐藏默认 UI,通过 <slot> 插槽注入自定义控制栏
- 多实例 — 支持同页多个 d-video 实例,各自独立引擎
快速开始
# 安卓
cli launch app-android --project <path> --playground custom --customType local --cleanCache true
# H5
cli launch web --project <path>
使用
<d-video
ref="playerRef"
:src="videoUrl"
:autoplay="false"
:live="false"
:muted="false"
:danmuBtn="true"
:enableDanmu="true"
:danmuList="danmuList"
:showMuteBtn="true"
@statechange="onStateChange"
@progress=""
@prepared="onPrepared"
@fullscreenchange=""
/>
自定义 UI(Slot 插槽)
传 controls="false" 隐藏默认 UI,通过 <slot> 注入自定义控制栏:
<d-video ref="playerRef" :src="videoUrl" :controls="false" :showCenterPlayBtn="false" :showLoading="false">
<!-- 自定义播放按钮 -->
<view class="my-overlay" v-if="!playing">
<text class="my-play-btn" @click="playerRef?.play()">▶</text>
</view>
<!-- 自定义控制栏 -->
<view class="my-controls">
<text>{{ formatTime(position) }} / {{ formatTime(duration) }}</text>
<text @click="playerRef?.toggle()">{{ playing ? '⏸' : '▶' }}</text>
<text @click="playerRef?.toggleFullscreen()">⛶</text>
</view>
</d-video>
多实例视频列表
<scroll-view>
<view v-for="(item, idx) in videoList" :key="idx">
<d-video
:ref="(el: any) => onPlayerRef(el, idx)"
:src="item.src"
:controls="false"
:danmuBtn="false"
@statechange="(e: any) => onStateChange(e, idx)"
@progress="(e: any) => (e, idx)"
></d-video>
<text>{{ item.title }}</text>
</view>
</scroll-view>
直播模式
<d-video
:src="hlsUrl"
:live="true"
:autoplay="true"
@livereconnect="onReconnect"
/>
直播模式下自动隐藏进度条、倍速控制;断流触发 livereconnect 事件。
支持协议
| 协议 |
示例 |
| RTMP |
rtmp://192.168.0.182:1936/test |
| RTSP |
rtsp://192.168.0.182:8554/test |
| HLS |
https://192.168.0.182:8888/test/index.m3u8 |
| WebRTC |
http://192.168.0.182:8889/test |
| FLV |
https://example.com/live.flv |
组件 API
Props
| 属性 |
类型 |
默认值 |
说明 |
| src |
string |
— |
视频 URL |
| controls |
boolean |
true |
显示默认控制栏 |
| autoplay |
boolean |
false |
自动播放 |
| live |
boolean |
false |
直播模式 |
| muted |
boolean |
false |
静音 |
| loop |
boolean |
false |
循环 |
| playbackRate |
number |
1.0 |
倍速 |
| objectFit |
string |
'contain' |
填充模式 |
| title |
string |
'' |
全屏标题 |
| danmuBtn |
boolean |
false |
显示弹幕开关 |
| enableDanmu |
boolean |
false |
开启弹幕 |
| danmuList |
Danmu[] |
[] |
弹幕列表 |
| showMuteBtn |
boolean |
false |
显示静音按钮 |
| showFullscreenBtn |
boolean |
true |
显示全屏按钮 |
| showPlayBtn |
boolean |
true |
显示播放按钮 |
| showCenterPlayBtn |
boolean |
true |
显示中央播放按钮 |
| showLoading |
boolean |
true |
显示加载指示 |
Methods
| 方法 |
说明 |
| play() |
播放 |
| pause() |
暂停 |
| stop() |
停止 |
| seek(ms) |
跳转(毫秒) |
| toggle() |
播放/暂停切换 |
| mute(muted) |
静音/取消 |
| playbackRate(rate) |
设置倍速 |
| requestFullscreen() |
进入全屏 |
| exitFullscreen() |
退出全屏 |
| toggleFullscreen() |
全屏切换 |
| getCurrentState() |
当前状态 |
| getPosition() |
当前位置(ms) |
| getDuration() |
总时长(ms) |
| switchQuality(index) |
切换清晰度 |
| switchSource(url) |
切换视频源(Vapor 模式需直接调用) |
Events
| 事件 |
说明 |
| statechange |
播放状态变化 |
| progress |
播放进度 |
| prepared |
就绪 |
| end |
播放结束 |
| error |
错误 |
| fullscreenchange |
全屏变化 |
| livereconnect |
直播重连 |
Iconfont 用法
/* App.uvue 全局加载 */
@font-face {
font-family: 'dplayer-iconfont';
src: url('/static/dplayer-iconfont.ttf');
}
<!-- 模板中用 HTML 实体,不要用 JS 转义 -->
<text style="font-family: 'dplayer-iconfont';"></text>
<!-- 动态切换可用 JS 字符串 -->
<text>{{ playing ? '\ue60f' : '\ue612' }}</text>
| 图标 |
码点 |
HTML 实体 |
| 播放 |
U+E612 |
 |
| 暂停 |
U+E60F |
 |
| 全屏进入 |
U+E610 |
 |
| 全屏退出 |
U+E611 |
 |
| 音量 |
U+E615 |
 |
| 静音 |
U+E617 |
 |
注意:字体文件不含 U+E601,返回按钮使用 Unicode 箭头 ← 代替。
Demo 页面
| 页面 |
路径 |
说明 |
| 蒸汽模式 Demo |
pages/vapor/index |
多实例视频列表 + 弹幕 + 全屏 |
| 官方式 Demo |
pages/d-video/index |
对齐 uni-video |
| HLS 直播 Demo |
pages/live/index |
直播流 + 断流重连 |
| 自定义 UI Demo |
pages/custom-ui/index |
slot 插槽自定义控制栏 |
平台支持
| 平台 |
引擎 |
全屏方式 |
| Android |
libmpv (native-view) |
沉浸式 + requestedOrientation |
| iOS |
libmpv (native-view) |
$setPageStyle 横屏 |
| 鸿蒙 |
libmpv (native-view) |
$setPageStyle 横屏 |
| H5 |
内置 <video> |
DOM Fullscreen API |
注意事项
- 蒸汽模式不支持 rpx — Vapor 模式下
rpx 会被当作固定像素值,不随屏幕适配缩放,请统一使用 px(2rpx = 1px)
- 退出全屏字体变大 — 全屏状态下
100vw/100vh 计算会因方向切换导致 UI 异常,建议全屏/非全屏使用不同的控制栏样式,或通过 fullscreenchange 事件监听后主动切换
- Vapor 模式 watch 不触发 —
watch(() => props.src) 在 Vapor 模式下不会触发,需通过 switchSource(url) 方法直接切换视频源
- CSS @keyframes 不可用 — Vapor 模式下 CSS 动画不生效,弹幕等动效请使用
v-for + setInterval 推进
- Math.random() 不生效 — Vapor 模式下返回 0,需使用自定义伪随机(如 LCG)
- Element.animate() 不支持 — Vapor 模式下不可用,需手动操作样式
- iOS 事件对象 — 自定义 UI 中读取事件数据时,需兼容属性访问和 Map.get() 两种方式
许可
MIT