更新记录

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 桥接后不是 UTSJSONObjectas! 强转中止应用;改用 instanceof 判断 + JSON.parse(JSON.stringify()) 兜底安全转换
  • 【Web 同名冲突修复】修复 this.showControls is not a function:Web 端 showControls() 方法与 Boolean prop show-controls 冲突,与 Harmony 同步改名 revealControls()(6 处调用)
  • 【iOS/Android 弹幕开关加固】toggle-danmaku 回调内直接内联启停/清屏逻辑(startDanmakuLoop/clearActive/dispatchDueDanmakustopDanmakuLoop/clearActive),不再依赖 watch 时序,规避安卓弹幕残留但冻结问题
  • 【发送弹幕】demo 页新增发送弹幕卡片(输入 + 发送 + 滚动/顶部/底部切换),向 danmaku-list push 新项即刻入场(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小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(5.0)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - - - -

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 秒自动隐藏,暂停/未播放常驻;点击画面显示

安装

  1. d-video-uid-player-video 复制到项目的 uni_modules/ 目录(easycom 自动注册,无需 pages.json 配置)
  2. 在页面中使用

基础用法

<template>
  <d-player-video
    ref="player"
    src="https://example.com/video.mp4"
    :show-controls="false"
    :muted="muted"
    @statechange="onStateChange"
    @progress=""
  >
    <!-- 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

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。