# video

Component Type:UniVideoElement

视频

# # Attributes

name type default description
loop boolean false 是否循环播放
src string(string.VideoURIString) - 视频资源地址
initial-time number - 指定视频初始播放位置
duration number - 指定视频长度
controls boolean true 是否显示默认播放控件(播放/暂停按钮、播放进度、时间)
danmu-list Array - 弹幕列表
danmu-btn boolean false 是否显示弹幕按钮,只在初始化时有效,不能动态变更
enable-danmu boolean false 是否展示弹幕,只在初始化时有效,不能动态变更
autoplay boolean false 是否自动播放
muted boolean false 是否静音播放
page-gesture boolean false 在非全屏模式下,是否开启亮度与音量调节手势
direction number -90 设置全屏时视频的方向,不指定则根据宽高比自动判断。有效值为 0(正常竖向), 90(屏幕逆时针90度), -90(屏幕顺时针90度)
show-progress boolean true 若不设置,宽度大于240时才会显示
show-fullscreen-btn boolean true 是否显示全屏按钮
show-play-btn boolean true 是否显示视频底部控制栏的播放按钮
show-center-play-btn boolean true 是否显示视频中间的播放按钮
show-loading boolean true 是否显示loading控件
enable-progress-gesture boolean true 是否开启控制进度的手势
objectFit string contain 当视频大小与 video 容器大小不一致时,视频的表现形式。 objectFit
poster string - 视频封面的图片网络资源地址,如果 controls 属性值为 false 则设置 poster 无效
show-mute-btn boolean false 是否显示静音按钮
title string - 视频的标题,全屏时在顶部展示
play-btn-position string - 播放按钮的位置
enable-play-gesture boolean false 是否开启播放手势,即双击切换播放、暂停
auto-pause-if-navigate boolean - 当跳转到其它小程序页面时,是否自动暂停本页面的视频
auto-pause-if-open-native boolean - 当跳转到其它微信原生页面时,是否自动暂停本页面的视频
vslide-gesture boolean false 在非全屏模式下,是否开启亮度与音量调节手势(同 page-gesture)
vslide-gesture-in-fullscreen boolean true 在全屏模式下,是否开启亮度与音量调节手势
ad-unit-id string - 视频前贴广告单元ID
poster-for-crawler string - 用于给搜索等场景作为视频封面展示,建议使用无播放 icon 的视频封面图,只支持网络地址
codec string hardware 解码器选择
http-cache boolean false 是否对 http、https 视频源开启本地缓存
play-strategy number 0 播放策略
is-live boolean - 是否为直播源
@play (event: Event) => void - 当开始/继续播放时触发
@pause (event: Event) => void - 当暂停播放时触发
@ended (event: Event) => void - 当播放到视频末尾时触发
@timeupdate (event: VideoTimeUpdateEvent) => void - 播放进度变化时触发,event.detail = { currentTime, duration }。触发频率 250ms 一次
@fullscreenchange (event: VideoFullScreenChangeEvent) => void - 当视频进入和退出全屏时触发,event.detail = { fullScreen, direction },direction取为 vertical 或 horizontal
@waiting (event: Event) => void - 视频出现缓冲时触发
@error (event: VideoErrorEvent) => void - 播放出错时触发
@progress (event: VideoProgressEvent) => void - 加载进度变化时触发,只支持一段加载。event.detail = { buffered },百分比
@fullscreenclick (event: VideoFullScreenClickEvent) => void - 视频全屏播放时点击屏幕触发。event.detail = { screenX, screenY, screenWidth, screenHeight }
@controlstoggle (event: VideoControlsToggleEvent) => void - 切换 controls 显示隐藏时触发。event.detail = { show }

# # objectFit

name description
contain 包含
fill 填充
cover 覆盖

# # Event

# # VideoTimeUpdateEvent

timeupdate 事件 播放进度变化时触发

# # VideoTimeUpdateEvent Values
name type required default description
detail VideoTimeUpdateEventDetail YES - -
type string YES - -
target Element NO - -
currentTarget Element NO - -
timeStamp Long YES - -

# # VideoFullScreenChangeEvent

fullscreenchange 事件 当视频进入和退出全屏是触发

# # VideoFullScreenChangeEvent Values
name type required default description
detail VideoFullScreenChangeEventDetail YES - -
type string YES - -
target Element NO - -
currentTarget Element NO - -
timeStamp Long YES - -

# # VideoErrorEvent

error 事件 视频播放出错时触发

# # VideoErrorEvent Values
name type required default description
detail VideoError YES - -
type string YES - -
target Element NO - -
currentTarget Element NO - -
timeStamp Long YES - -
# # VideoError Values
name type optinal default description
errCode VideoErrorCode YES - -
errSubject string YES - 统一错误主题(模块)名称
data any NO - 错误信息中包含的数据
errMsg string YES - -

# # VideoProgressEvent

progress 事件 加载进度变化时触发

# # VideoProgressEvent Values
name type required default description
detail VideoProgressEventDetail YES - -
type string YES - -
target Element NO - -
currentTarget Element NO - -
timeStamp Long YES - -

# # VideoFullScreenClickEvent

fullscreenclick 事件 视频播放全屏播放时点击事件

# # VideoFullScreenClickEvent Values
name type required default description
detail VideoFullScreenClickEventDetail YES - -
type string YES - -
target Element NO - -
currentTarget Element NO - -
timeStamp Long YES - -

# # VideoControlsToggleEvent

controlstoggle 事件 切换播放控件显示隐藏时触发

# # VideoControlsToggleEvent Values
name type required default description
detail VideoControlsToggleEventDetail YES - -
type string YES - -
target Element NO - -
currentTarget Element NO - -
timeStamp Long YES - -

# # UniVideoElement

video元素对象

# # UniVideoElement Methods

# # play()

播放

# # pause()

暂停

# # seek(position)

跳转到指定位置

# # Parameters
name type required default description
position number YES - 跳转到指定位置(秒)
# # stop()

停止视频

# # sendDanmu(danmu)

发送弹幕

# # Parameters
name type required default description
danmu Danmu YES - 弹幕数据
# # Danmu Values
name type optinal default description
text string NO - 弹幕文字
color string NO - 弹幕颜色
time number NO - 显示时刻
# # playbackRate(rate)

设置倍速播放

# # Parameters
name type required default description
rate number YES - 支持倍率 0.5/0.8/1.0/1.25/1.5
# # requestFullScreen(direction)

进入全屏

# # Parameters
name type required default description
direction RequestFullScreenOptions YES - 0|正常竖向, 90|屏幕逆时针90度, -90|屏幕顺时针90度
# # RequestFullScreenOptions Values
name type optinal default description
direction number NO - direction - 0: 正常竖向 - 90: 屏幕逆时针90度 - -90: 屏幕顺时针90度
# # exitFullScreen()

退出全屏

# 视频格式

  • mp4
  • m4v
  • mov
  • webm
  • 3gp
  • flv
  • m3u8 (本地m3u8文件需3.99+)

# # Example

hello uni-app x

<template>
 <view class="uni-flex-item">
   <video class="video" ref="video" id="video" :header="header" :src=src :autoplay="autoplay" :loop="loop"
     :muted="muted" :initial-time="initialTime" :duration="duration" :controls="controls" :danmu-btn="danmuBtn"
     :enable-danmu="enableDanmu" :page-gesture="pageGesture" :direction="direction" :show-progress="showProgress"
     :show-fullscreen-btn="showFullscreenBtn" :show-play-btn="showPlayBtn" :show-center-play-btn="showCenterPlayBtn"
     :show-loading="showLoading" :enable-progress-gesture="enableProgressGesture" :object-fit="objectFit"
     :poster="poster" :show-mute-btn="showMuteBtn" :title="title" :enable-play-gesture="enablePlayGesture"
     :vslide-gesture="vslideGesture" :vslide-gesture-in-fullscreen="vslideGestureInFullscreen" :codec="codec"
     :http-cache="httpCache" :play-strategy="playStrategy" :danmu-list="danmuList" @play="onPlay" @pause="onPause"
     @ended="onEnded" @timeupdate="onTimeUpdate" @waiting="onWaiting" @error="onError" @progress="onProgress"
     @fullscreenclick="onFullScreenClick" @controlstoggle="onControlsToggle" @fullscreenchange="onFullScreenChange">
   </video>
   <scroll-view class="uni-padding-wrap uni-common-mt uni-flex-item">
     <view class="uni-title">
       <text class="uni-title-text">API示例</text>
     </View>
     <view class="uni-btn-v">
       <button type="primary" @click="play">播放</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="pause">暂停</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="seek(pos)">跳转到指定位置</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="requestFullScreen(requestFullScreenOptions)">进入全屏</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="exitFullScreen">退出全屏</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="stop">停止</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="sendDanmu(danmu)">发送弹幕</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="playbackRate(rate)">设置倍速</button>
     </view>
     <view class="uni-title">
       <text class="uni-title-text">属性示例</text>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setSrc(_src)">设置播放资源</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setAutoplay()">设置是否自动播放(未播放时设置有效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setLoop()">设置是否循环播放(本次播放完成后生效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setMuted()">设置是否静音播放</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setInitialTime(_initialTime)">设置初始播放位置(本次播放完成后生效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setDuration(_duration)">设置视频时长(未播放时设置有效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setControls()">设置是否显示默认播放控件</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setDanmuBtn()">设置是否显示弹幕按钮</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setPageGesture()">非全屏模式下,设置是否开启亮度与音量调节手势</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setDirection(_direction)">设置全屏时视频的方向</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setShowProgress()">设置是否显示进度条</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setShowFullscreenBtn()">设置是否显示全屏按钮</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setShowPlayBtn()">设置是否显示视频底部控制栏的播放按钮</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setShowCenterPlayBtn()">设置是否显示视频中间的播放按钮</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setShowLoading()">设置是否显示loading控件</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setEnableProgressGesture()">设置是否开启控制进度的手势</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setObjectFit(_objectFit)">设置视频大小与video容器大小不一致时,视频的表现形式</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setPoster(_poster)">设置视频封面</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setShowMuteBtn()">设置是否显示静音按钮</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setTitle(_title)">设置视频标题</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setEnablePlayGesture()">设置是否开启播放手势</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setVslideGesture()">非全屏模式下,设置是否开启亮度与音量调节手势</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setVslideGestureInFullscreen()">全屏模式下,设置是否开启亮度与音量调节手势</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setCodec(_codec)">设置解码器(未播放时设置有效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setHttpCache()">设置是否对http、https视频源开启本地缓存(未播放时设置有效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setPlayStrategy(_playStrategy)">设置播放策略(未播放时设置有效)</button>
     </view>
     <view class="uni-btn-v">
       <button type="primary" @click="setHeader(_header)">设置header</button>
     </view>
   </scroll-view>
 </view>
</template>

<script lang="uts">
 export default {
   onReady() {
     this.videoContext = uni.createVideoContext('video', this);
   },
   data() {
     return {
       videoContext: null as VideoContext | null,
       // 属性
       src: "https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/%E7%AC%AC1%E8%AE%B2%EF%BC%88uni-app%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%89-%20DCloud%E5%AE%98%E6%96%B9%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B@20181126-lite.m4v",
       _src: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-app-video-courses.mp4",
       autoplay: false,
       loop: false,
       muted: false,
       initialTime: 0,
       _initialTime: 6,
       duration: -1,
       _duration: 60,
       controls: true,
       danmuList: [{
         text: '要显示的文本',
         color: '#FF0000',
         time: 3
       }, {
         text: '要显示的文本2',
         color: '#31ff23',
         time: 5
       }, {
         text: '要显示的文本3',
         color: '#f13ef8',
         time: 7
       }, {
         text: '要显示的文本4',
         color: '#4972f8',
         time: 9
       }, {
         text: '要显示的文本5',
         color: '#000000',
         time: 11
       }] as Array<Danmu>,
       danmuBtn: false,
       enableDanmu: true,
       pageGesture: false,
       direction: -90,
       _direction: 0,
       requestFullScreenOptions: {
         direction: -90
       } as RequestFullScreenOptions,
       showProgress: true,
       showFullscreenBtn: true,
       showPlayBtn: true,
       showCenterPlayBtn: true,
       showLoading: true,
       enableProgressGesture: true,
       objectFit: "contain",
       _objectFit: "fill",
       poster: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-android.png",
       _poster: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-ios.png",
       showMuteBtn: false,
       title: "video-component",
       _title: "video-component video-component",
       enablePlayGesture: false,
       vslideGesture: false,
       vslideGestureInFullscreen: true,
       codec: "hardware",
       _codec: "software",
       httpCache: true,
       playStrategy: 0,
       _playStrategy: 2,
       header: {
         'User-Agent': 'header test'
       } as UTSJSONObject,
       _header: {
         'User-Agent': 'header test2'
       } as UTSJSONObject,
       // API
       pos: 10,
       rate: 1.5,
       danmu: {
         text: '要显示的文本',
         color: '#FF0000'
       } as Danmu,
       // 自动化测试
       isPlaying: false,
       isPause: false,
       isFullScreen: false
     }
   },
   methods: {
     // API
     play: function () {
       console.log("play");
       this.videoContext?.play();
     },
     pause: function () {
       console.log("pause");
       (uni.getElementById("video") as UniVideoElement).pause(); //as写法测试。注意id不对时as会崩溃
       // this.videoContext?.pause();
     },
     seek: function (pos : number) {
       console.log("seek -> " + pos);
       this.videoContext?.seek(pos);
     },
     requestFullScreen: function (options : RequestFullScreenOptions) {
       console.log("requestFullScreen -> " + options);
       this.videoContext?.requestFullScreen(options);
     },
     exitFullScreen: function () {
       console.log("exitFullScreen");
       this.videoContext?.exitFullScreen();
     },
     stop: function () {
       console.log("stop");
       uni.getElementById<UniVideoElement>("video")?.stop(); //泛型写法测试
       // this.videoContext?.stop();
     },
     sendDanmu: function (danmu : Danmu) {
       console.log("sendDanmu -> " + danmu);
       this.videoContext?.sendDanmu(danmu);
     },
     playbackRate: function (rate : number) {
       console.log("playbackRate -> " + rate);
       this.videoContext?.playbackRate(rate);
     },
     // 属性
     setSrc: function (src : string) {
       this.src = src;
       console.log("src -> " + this.src)
     },
     setAutoplay: function () {
       this.autoplay = !this.autoplay;
       console.log("autoplay -> " + this.autoplay)
     },
     setLoop: function () {
       this.loop = !this.loop;
       console.log("loop -> " + this.loop)
     },
     setMuted: function () {
       this.muted = !this.muted;
       console.log("muted -> " + this.muted)
     },
     setInitialTime: function (initialTime : number) {
       this.initialTime = initialTime;
       console.log("initialTime -> " + this.initialTime)
     },
     setDuration: function (duration : number) {
       this.duration = duration;
       console.log("duration -> " + this.duration)
     },
     setControls: function () {
       this.controls = !this.controls;
       console.log("controls -> " + this.controls)
     },
     setDanmuBtn: function () {
       this.danmuBtn = !this.danmuBtn;
       console.log("danmuBtn -> " + this.danmuBtn)
     },
     setPageGesture: function () {
       this.pageGesture = !this.pageGesture;
       console.log("pageGesture -> " + this.pageGesture)
     },
     setDirection: function (direction : number) {
       this.direction = direction;
       console.log("direction -> " + this.direction)
     },
     setShowProgress: function () {
       this.showProgress = !this.showProgress;
       console.log("showProgress -> " + this.showProgress)
     },
     setShowFullscreenBtn: function () {
       this.showFullscreenBtn = !this.showFullscreenBtn;
       console.log("showFullscreenBtn -> " + this.showFullscreenBtn)
     },
     setShowPlayBtn: function () {
       this.showPlayBtn = !this.showPlayBtn;
       console.log("showPlayBtn -> " + this.showPlayBtn)
     },
     setShowCenterPlayBtn: function () {
       this.showCenterPlayBtn = !this.showCenterPlayBtn;
       console.log("showCenterPlayBtn -> " + this.showCenterPlayBtn)
     },
     setShowLoading: function () {
       this.showLoading = !this.showLoading;
       console.log("showLoading -> " + this.showLoading)
     },
     setEnableProgressGesture: function () {
       this.enableProgressGesture = !this.enableProgressGesture;
       console.log("enableProgressGesture -> " + this.enableProgressGesture)
     },
     setObjectFit: function (objectFit : string) {
       this.objectFit = objectFit;
       console.log("objectFit -> " + this.objectFit)
     },
     setPoster: function (poster : string) {
       this.poster = poster;
       console.log("poster -> " + this.poster)
     },
     setShowMuteBtn: function () {
       this.showMuteBtn = !this.showMuteBtn;
       console.log("showMuteBtn -> " + this.showMuteBtn)
     },
     setTitle: function (title : string) {
       this.title = title;
       console.log("title -> " + this.title)
     },
     setEnablePlayGesture: function () {
       this.enablePlayGesture = !this.enablePlayGesture;
       console.log("enablePlayGesture -> " + this.enablePlayGesture)
     },
     setVslideGesture: function () {
       this.vslideGesture = !this.vslideGesture;
       console.log("vslideGesture -> " + this.vslideGesture)
     },
     setVslideGestureInFullscreen: function () {
       this.vslideGestureInFullscreen = !this.vslideGestureInFullscreen;
       console.log("vslideGestureInFullscreen -> " + this.vslideGestureInFullscreen)
     },
     setCodec: function (codec : string) {
       this.codec = codec;
       console.log("codec -> " + this.codec)
     },
     setHttpCache: function () {
       this.httpCache = !this.httpCache;
       console.log("httpCache -> " + this.httpCache)
     },
     setPlayStrategy: function (playStrategy : number) {
       this.playStrategy = playStrategy;
       console.log("playStrategy -> " + this.playStrategy)
     },
     setHeader: function (header : UTSJSONObject) {
       this.header = header;
       console.log("header -> " + this.header)
     },
     // 事件
     onPlay: function (res : Event) {
       console.log(res.type);
       this.isPlaying = true;
       this.isPause = false;
     },
     onPause: function (res : Event) {
       console.log(res.type);
       this.isPlaying = false;
       this.isPause = true;
     },
     onEnded: function (res : Event) {
       console.log(res.type);
     },
     onTimeUpdate: function (res : VideoTimeUpdateEvent) {
       console.log(res.type + " -> " + JSON.stringify(res.detail));
     },
     onFullScreenChange: function (res : VideoFullScreenChangeEvent) {
       console.log(res.type + " -> " + JSON.stringify(res.detail));
       this.isFullScreen = !this.isFullScreen;
     },
     onWaiting: function (res : Event) {
       console.log(res.type);
     },
     onError: function (res : VideoErrorEvent) {
       console.log(res.type + " -> " + JSON.stringify(res.detail));
     },
     onProgress: function (res : VideoProgressEvent) {
       console.log(res.type + " -> " + JSON.stringify(res.detail));
     },
     onFullScreenClick: function (res : VideoFullScreenClickEvent) {
       console.log(res.type + " -> " + JSON.stringify(res.detail));
     },
     onControlsToggle: function (res : VideoControlsToggleEvent) {
       console.log(res.type + " -> " + JSON.stringify(res.detail));
     },
     // 自动化测试
     playTest: function () {
       this.videoContext?.play();
     },
     pauseTest: function () {
       this.videoContext?.pause();
     },
     requestFullScreenTest: function () {
       const options : RequestFullScreenOptions = {
         direction: -90
       };
       this.videoContext?.requestFullScreen(options);
     },
     exitFullScreenTest: function () {
       this.videoContext?.exitFullScreen();
     },
     stopTest: function () {
       this.videoContext?.stop();
     }
   }
 }
</script>

<style>
 .video {
   width: 750rpx;
   height: 400rpx;
 }
</style>

# # Compatibility

Android version Android uni-app Android uni-app-x iOS version iOS uni-app iOS uni-app-x
video 5.0 3.9+ 9.0 -
play-btn-position 5.0 x x 9.0 x -
auto-pause-if-navigate 5.0 x x 9.0 x -
auto-pause-if-open-native 5.0 x x 9.0 x -
ad-unit-id 5.0 x x 9.0 x -
poster-for-crawler 5.0 x x 9.0 x -
is-live 5.0 x x 9.0 x -

# App平台

App-Android平台video组件使用ijkplayer库实现:https://github.com/bilibili/ijkplayer

弹幕功能使用DanmakuFlameMaster库实现:https://github.com/bilibili/DanmakuFlameMaster

ijkplayer库的功能较多,video组件并非完全封装。有需要的开发者可以使用uts直接操作该库。

video组件的源码详见。下载该uni_modules到工程下,修改源码打包,可覆盖内置的video组件。

另外ijkplayer作为一个开源库,比腾讯视频等商业sdk仍有差距。如无法在开源库上满足需求,可在插件市场寻找商业sdk插件:腾讯视频阿里云视频

# # Children Components

Can't nest components

# 上下文对象API

video的操作api为uni.createVideoContext()

给video组件设一个id属性,将id的值传入uni.createVideoContext(),即可得到video组件的上下文对象,进一步可使用.play().stop()等方法。

# # See also

# Bug & Tips

  • 暂不支持横屏全屏后放置子组件
  • 标准运行基座默认不包含intel x86 cpu的兼容so库,所以video组件在标准基座运行时无法在x86 cpu的设备上运行(常见于模拟器)。如需支持x86 cpu,请在manifest里配置abiFilters,打包或自定义基座后生效 详见
  • 本地视频文件,或者静态引用(HBuilderX 3.97+)、或者import导入文件、或者在static目录下(项目下或uni_modules下都支持static目录),否则文件不会被copy到最终的包中,导致无法访问。
  • 默认拦截触摸事件,目前会导致父组件无法响应触摸事件