更新记录
1.2.1(2026-09-19)
增加demo
1.2.0(2026-09-19)
- 【Android 崩溃修复】修复点击播放按钮 NPE:
toggle-play/cycle-speed/toggle-mute/toggle-fullscreen/toggle-danmaku五处$emit未带 payload,框架传null,而页面 handler 的(e: any)编译为 Kotlin 非空参数,包装 lambda 入参 null 检查直接抛NullPointerException(getEventValue的 null 保护因在函数体内而无效);五处均补齐Mappayload,key 与 iOS 端对齐(playing/speed/muted/fullscreen/enabled)。根因为1.1.0遗留问题,安卓端点击播放一直在此崩溃 - 【iOS 新增 API】新增
syncState(playing, speed, muted, fullscreen, position, duration)与setPlayer(player)并加入expose:iOS 隐藏 placeholder 组件的 props 桥接不可靠,改由页面直读 player 六个 getter 后显式推送,六项状态与播放器实时一致。安卓 / Web / Harmony 由 props + watch 自动同步,不需要此通道 - 【iOS 布局稳定性】
syncState改为 diff 驱动:仅fullscreen/playing变化时才触发布局与显隐处理,避免 250ms 进度推送把 3s 自动隐藏计时清零、控制栏不自动消失;resetHideTimer恢复为每次 clear + recreate 以避免点击后立即隐藏;startLayoutTimer增加重入保护,30 次仍未成功则恢复控制栏可见 - 【iOS 全屏转场】点击全屏时立即隐藏
controlBar消除转场残影,待layoutControlBar成功布局后再恢复;applyControlsVisibility仅控制bottomBar/centerBtn,与转场显隐互不干扰 - 【iOS 触摸穿透】
NVLoaded中隐藏返回的 placeholder 并置isUserInteractionEnabled = false,触摸穿透至 player containerView → customLayer → 控制栏,修复加载后控制栏不可点击 - 【字体自包含】
dplayer-iconfont.ttf拷贝至本插件static/目录,四端资源路径由/uni_modules/d-player-video/static/改为/uni_modules/d-video-ui/static/,不再隐式依赖 d-player-video 插件的字体文件
1.1.0(2026-09-18)
- 【Android 控制栏对齐】完全复刻 d-player-video 内置栏:中央 120px 圆形大播放按钮(ImageView + 半透明底 + 白色描边)、播放/暂停/音量/静音/全屏均改用矢量 Drawable 图标(优先加载 dplayer-iconfont.ttf,失败回退 Canvas Path 绘制),控制行 padding 改为
(42,10,22,12)、按钮宽 44、间距 20,与内置栏视觉一致 - 【iOS 崩溃修复】修复加载后
swift_dynamicCastFailure崩溃:danmaku-list元素经 iOS 桥接后不是UTSJSONObject,as!强转中止应用;改用instanceof判断 +JSON.parse(JSON.stringify())兜底安全转换 - 【Web 同名冲突修复】修复
this.showControls is not a function:Web 端showControls()方法与 Boolean propshow-controls冲突,与 Harmony 同步改名revealControls()(6 处调用) - 【iOS/Android 弹幕开关加固】
toggle-danmaku回调内直接内联启停/清屏逻辑(startDanmakuLoop/clearActive/dispatchDueDanmaku或stopDanmakuLoop/clearActive),不再依赖 watch 时序,规避安卓弹幕残留但冻结问题 - 【发送弹幕】demo 页新增发送弹幕卡片(输入 + 发送 + 滚动/顶部/底部切换),向
danmaku-listpush 新项即刻入场(time= 当前播放位置) - 【Harmony 触摸显示】弹幕层全屏
@click.stop=""吞掉点击,改为@click.stop="onSurfaceTap",修复鸿蒙端点击不显示控制栏 - 【Harmony 命名冲突】
showControls()方法与 prop 撞名(true is not callable),改名revealControls()(7 处调用) - 【文档】新增 README(安装、用法、Props/Events 协议、平台差异表)
平台兼容性
uni-app(5.0)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
d-video-ui 播放器控制栏
面向 uni-app x 的自定义播放器控制栏组件,与 d-player-video 播放器搭配使用。控制栏与弹幕引擎在 Android / iOS / HarmonyOS / Web 四端行为统一。
功能特性
- 四端统一控制栏:播放/暂停、进度条(拖动预览+跳转)、倍速切换、静音、全屏、弹幕开关,Android/iOS/Web/Harmony 交互一致
- 原生挂载(Android/iOS):通过
player.addCustomView()将原生控制栏挂到视频之上的customLayer,覆盖播放器内置控制栏(showControls=false) - Overlay 覆盖层(Web/Harmony):渲染为播放器 slot 内覆盖层,与内置栏样式对齐
- 弹幕引擎:滚动/顶部/底部三种弹幕类型,多轨道防碰撞,支持自定义颜色、字号、滚动速度
- 弹幕列表 prop 驱动:
danmaku-list数组变化实时生效,播放中发送的弹幕即刻入场 - 事件协议统一:
toggle-play / seek / cycle-speed / toggle-mute / toggle-fullscreen / toggle-danmaku四端 kebab-case - 控制栏显隐规则:播放中 3 秒自动隐藏,暂停/未播放常驻;点击画面显示
安装
- 将
d-video-ui与d-player-video复制到项目的uni_modules/目录(easycom 自动注册,无需pages.json配置) - 在页面中使用
基础用法
<template>
<d-player-video
ref="player"
src="https://example.com/video.mp4"
:show-controls="false"
:muted="muted"
@statechange="onStateChange"
@progress="onProgress"
>
<!-- Web / Harmony:d-video-ui 作为覆盖层内嵌到播放器 slot -->
<!-- #ifdef WEB || APP-HARMONY -->
<d-video-ui
ref="ui"
:duration="duration"
:position="position"
:is-playing="isPlaying"
:muted="muted"
:speed="playbackRate"
:danmaku-list="danmakuList"
@toggle-play="Play"
@seek=""
@cycle-speed="onCycleSpeed"
@toggle-mute="Mute"
@toggle-fullscreen="Fullscreen"
@toggle-danmaku="Danmaku"
/>
<!-- #endif -->
</d-player-video>
<!-- Android / iOS:d-video-ui 是原生组件(slot 不可用),作为兄弟节点绑定 -->
<!-- #ifdef APP-ANDROID || APP-IOS -->
<d-video-ui
ref="ui"
:duration="duration"
:position="position"
:is-playing="isPlaying"
:muted="muted"
:speed="playbackRate"
:danmaku-list="danmakuList"
@toggle-play="Play"
@seek=""
@cycle-speed="onCycleSpeed"
@toggle-mute="Mute"
@toggle-fullscreen="Fullscreen"
@toggle-danmaku="Danmaku"
/>
<!-- #endif -->
</template>
Android/iOS:把原生控制栏挂到播放器
原生端 d-video-ui 是原生组件,只渲染一个空的占位 View。真正的控制栏通过 getControlBarView() 获取后调用播放器的 addCustomView() 挂载:
// #ifdef APP-ANDROID || APP-IOS
onReady() {
setTimeout(() => {
this.mountNativeControlBar()
}, 300)
},
methods: {
mountNativeControlBar() {
const player = this.$refs.player as DPlayerVideoElement | null
const ui = this.$refs.ui as DVideoUiElement | null
if (player == null || ui == null) return false
const bar = ui.getControlBarView()
if (bar == null) return false
player.addCustomView(bar)
this.controlBarMounted = true
}
}
// #endif
pages.json 需声明两个原生组件:
{
"easycom": {
"custom": {
"d-player-video": {
"app-android": "d-player-video",
"app-ios": "d-player-video",
"app-harmony": "d-player-video"
},
"d-video-ui": {
"app-android": "d-video-ui",
"app-ios": "d-video-ui",
"app-harmony": "d-video-ui"
}
}
}
}
Props
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
duration |
Number | 0 | 视频总时长(ms) |
position |
Number | 0 | 当前播放位置(ms),驱动进度条与弹幕调度 |
is-playing |
Boolean | false | 是否播放中 |
muted |
Boolean | false | 是否静音 |
speed |
Number | 1.0 | 播放倍速,用于显示与循环切换 |
live |
Boolean | false | 是否直播(直播不显示进度条) |
show-controls |
Boolean | true | 控制栏是否显示 |
is-fullscreen |
Boolean | false | 是否全屏,用于切换全屏图标 |
danmaku-list |
Array | [] | 弹幕列表,元素见下 |
danmaku-list 元素
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Number | 是 | 弹幕唯一标识 |
time |
Number | 是 | 弹幕出现的播放时刻(ms) |
text |
String | 是 | 弹幕内容 |
type |
String | 否 | scroll 滚动(默认)/ top 顶部 / bottom 底部 |
color |
String | 否 | 颜色,CSS 格式 #rrggbb,默认 #ffffff |
fontSize |
Number | 否 | 字号(px),默认 14 |
speed |
Number | 否 | 滚动速度(px/s),仅 scroll 有效,默认 90 |
Events
事件载荷统一为 Map<string, any>(原生端)或普通对象(Web)。
| 事件 | 载荷 | 说明 |
|---|---|---|
@toggle-play |
{} |
点击播放/暂停 |
@seek |
{ ms: number } |
拖动进度条定位 |
@cycle-speed |
{} |
切换倍速 |
@toggle-mute |
{} |
切换静音 |
@toggle-fullscreen |
{} |
切换全屏 |
@toggle-danmaku |
{} |
切换弹幕开关 |
发送弹幕
向 danmaku-list push 新元素即可(id 递增、time 用当前播放位置),播放中由 position 变化驱动弹幕即刻入场;暂停时发送的弹幕会等到恢复播放后才入场。参考 demo/pages/custom-ui/index.uvue。
平台差异
| 平台 | 控制栏实现 | 触摸显示控制栏 | 图标 |
|---|---|---|---|
| Android | 原生 LinearLayout + TextView/SeekBar,drawable 图标 | SurfaceView 触摸回调 | iconfont(dplayer-iconfont.ttf),回退 Canvas Path 矢量绘制 |
| iOS | 原生 UIView + UILabel/UISlider/UIButton | UITapGestureRecognizer(cancelsTouchesInView=false) |
图标文本 + 系统 SF Symbols 近似 |
| Harmony | ArkUI 覆盖层 | 弹幕层 @click.stop 透传 + 控制层点击 |
文本字形 |
| Web | DOM 覆盖层 | 点击/触摸事件 | 文本字形 |
Changelog
见 changelog.md。

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 108
赞赏 0
下载 12748339
赞赏 1959
赞赏
京公网安备:11010802035340号