微信小程序video控件的使用
微信小程序video控件的使用
一、简介
video控件是微信小程序提供的系统组件之一,用于实现播放视频的功能。
二、属性
| 属性名 | 类型 | 默认值 | 说明 | 最低版本 |
|——–|——–|——–|——–|——–|
| src | String| | 要播放视频的资源地址 | |
| initial-time| String | | 指定视频初始播放位置| 1.6.0 |
| duration |Number|| 指定视频时长 | 1.1.0 |
| controls |Boolean |true| 是否显示默认播放控件(播放/暂停按钮、播放进度、时间)| |
| danmu-list |Object Array||弹幕列表 | |
| danmu-btn |Boolean|false | 是否显示弹幕按钮,只在初始化时有效,不能动态变更| |
| enable-danmu |Boolean|false| 是否展示弹幕,只在初始化时有效,不能动态变更 | |
|autoplay|Boolean|false|是否自动播放| |
|loop|Boolean|false|是否循环播放| 1.4.0 |
|muted|Boolean|false|是否静音播放| 1.4.0 |
|page-gesture|Boolean|false|在非全屏模式下,是否开启亮度与音量调节手势|1.6.0 |
|direction|Number||设置全屏时视频的方向,不指定则根据宽高比自动判断。有效值为 0(正常竖向), 90(屏幕逆时针90度), -90(屏幕顺时针90度)|1.7.0|
|bindplay|EventHandle||当开始/继续播放时触发play事件| |
|bindpause|EventHandle||当暂停播放时触发 pause 事件| |
|bindended|EventHandle||当播放到末尾时触发 ended 事件| |
|bindtimeupdate|EventHandle||播放进度变化时触发,event.detail = {currentTime, duration} 。触发频率 250ms 一次| |
|bindfullscreenchange|EventHandle||当视频进入和退出全屏是触发,event.detail = {fullScreen, direction},direction取为 vertical 或 horizontal| |
|objectFit|String|contain|当视频大小与 video 容器大小不一致时,视频的表现形式。contain:包含,fill:填充,cover:覆盖| 1.4.0|
|poster|String||视频封面的图片网络资源地址,如果 controls 属性值为 false 则设置 poster 无效| |
||||||
video 组件 默认宽度300px、高度225px,可通过wxss设置宽高。
三、相关实现api
1、wx.createVideoContext
创建并返回 video 上下文 videoContext 对象。在自定义组件下,第二个参数传入组件实例this,以操作组件内 video 组件
2、videoContext对象
videoContext 通过 videoId 跟一个 video 组件绑定,通过它可以操作一个 video 组件。
videoContext 对象的方法列表:
| 方法 | 参数 | 说明 | 最低版本 |
|——–|——–|——–|——–|
|play | 无| 播放 | |
|pause| 无| 暂停 | |
|seek | position| 跳转到指定位置,单位 s| |
|sendDanmu|danmu|发送弹幕,danmu 包含两个属性 text, color。||
|sendDanmu|danmu|发送弹幕,danmu 包含两个属性 text, color。||
|sendDanmu|danmu|发送弹幕,danmu 包含两个属性 text, color。||
|playbackRate|rate|设置倍速播放,支持的倍率有 0.5/0.8/1.0/1.25/1.5|1.4.0|
|requestFullScreen|无|进入全屏,可传入{direction}参数(1.7.0起支持),详见video组件文档|1.4.0|
|exitFullScreen|无|退出全屏|1.4.0|
四、代码实现
在四川建设厅的代码实现中,我们未涉及弹幕功能的相关使用,所以以下代码不涉及弹幕的代码,如果想自己尝试使用,可以在官网查看其相关代码。
实现效果,如下图
实现原理:
在四川建设厅中,我们将视频播放控件进行了组件化的封装,将其放入一个名为courseVideoPlayer的组件中,组件的相关知识,可以查看佳斌写的自定义组件的实现,加以学习。
核心代码:
courseVideoPlayer.wxml
<view>
<!--poster="{{coverImageUrl}}" -->
<video id="myVideo" class="myVideo" src="{{playUrl}}" autoplay='false' controls='true' bindtimeupdate='timeUpdate' bindended='endAction'>
<!-- <cover-view bindtap='startFirstPlayAction' class='cover-view' wx:if="{{isShowCoverView}}"></cover-view> -->
<cover-view bindtap='_startFirstPlayAction' class='cover-view' wx:if="{{isShowCoverView}}">
<cover-image class='cover-view' src="{{coverImageUrl}}" mode="aspectFill"/>
<cover-image style='position:absolute; top:50%; left:50%; width:132rpx; height:132rpx; margin:-66rpx 0 0 -66rpx; z-index:10000' src="/image/video-play.png"/>
</cover-view>
</video>
</view>
这部分代码主要是视频界面部分,除了使用到video控件之外,我们还用到了cover-view以及cover-image组件,这两个组件的使用,在此,我做一下简单的介绍:
(1)cover-view:覆盖在原生组件之上的文本视图,可覆盖的原生组件包括map、video、canvas、camera,只支持嵌套cover-view、cover-image。
(2)cover-image:覆盖在原生组件之上的图片视图,可覆盖的原生组件同cover-view,支持嵌套在cover-view里。
属性:src String 图标路径,支持临时路径、网络地址(1.6.0起支持)。暂不支持base64格式。
按照功能来说,cover-view和cover-image实质上与普通的基础控件view与image无异,只是这两个控件特殊在,他可以覆盖在map、video、canvas、camera控件中,也正是因为这个特殊性,导致了他们在试用时也存在这一些差异,试用这两个控件的过程中,我们需要考虑以下几个注意点:
* Bug & Tips *
tip: 基础库 1.6.0 起支持css transition动画,transition-property只支持transform (translateX, translateY)与opacity。
tip: 基础库 1.6.0 起支持css opacity。
tip: 只可嵌套在原生组件map、video、canvas、camera内,避免嵌套在其他组件内。
tip: 事件模型遵循冒泡模型,但不会冒泡到原生组件。
tip: 文本建议都套上cover-view标签,避免排版错误。
tip: 只支持基本的定位、布局、文本样式。不支持设置单边的border、background-image、shadow、overflow等。
tip: 建议子节点不要溢出父节点
courseVideoPlayer.js
let studyPlayerManager = require('../../../../utils/studyManager/studyPlayerManager.js')
let currentTime = 0
let videoCtx = null
let app = getApp()
Component({
/**
* 组件的属性列表
*/
properties: {
playUrl:{
type:String,
value:'',
observer: function (newVal, oldVal) {
if (newVal.length){
videoCtx.play()
}
}
},
totalSecondsTime:{
type:Number,
value:10
},
playInfo:{
type: Object,
value: {},
observer: function (newVal, oldVal) {
}
},
coverImageUrl:{
type: String,
value: '../../../image/course-img.jpg',
observer: function (newVal, oldVal) {
}
},
isShowCoverView:{
type:Boolean,
value:true,
observer: function (newVal, oldVal) {
}
},
// 初始播放时间
initialTime : {
type:Number,
value:0
}
},
/**
* 组件的初始数据
*/
data: {
lastTime: 0,
zindex: Math.max,
currentTime: 0,
isTest:false
},
attached: function () {
wx.setStorageSync('lastTime', '0');
wx.setStorageSync('maxTime', '0');
videoCtx = wx.createVideoContext('myVideo', this)
// 初始化toast
new app.WeToast(this)
studyPlayerManager.initStudyPlayerManager(this)
},
moved: function () {
},
detached: function () {
this.studyPlayerManager.deallocStudyPlayerManager()
},
/**
* 组件的方法列表
*/
methods: {
play() {
videoCtx.play()
},
pause() {
videoCtx.pause()
},
timeUpdate(e) {
this.triggerEvent("videoTimeUpdate", e.detail.currentTime)
var maxTime = parseInt(wx.getStorageSync('maxTime'));
console.log('maxTime:' + maxTime);
var lastTime = parseInt(wx.getStorageSync('lastTime'));
console.log('lastTime:' + lastTime);
currentTime = e.detail.currentTime;
console.log('currentTime:' + currentTime)
if (currentTime != 0 && ((currentTime - lastTime) < 3)) {
wx.setStorageSync('lastTime', currentTime);
}
if (currentTime != 0 && currentTime > maxTime && (((currentTime - lastTime) > 0) && ((currentTime - lastTime) < 3))) {
wx.setStorageSync('maxTime', currentTime);
console.log('设置最大时间!')
}
if (!this.data.isTest && currentTime > maxTime) {
if ((currentTime - lastTime) > 3) {
//跳转到上次的进度
videoCtx.seek(maxTime);
wx.setStorageSync('lastTime', maxTime);
this.wetoast.toast({
title: '不能进行跳转!请认真学习'
})
}
}
},
endAction(e) {
let maxTime = parseInt(wx.getStorageSync('maxTime'));
if (!this.data.isTest && ((this.properties.totalSecondsTime - maxTime) > 3)) {
this.wetoast.toast({
title: '不能进行跳转!请认真学习'
})
videoCtx.seek(maxTime)
videoCtx.play()
}else{
this.triggerEvent("videoPlayEndEvent")
this._playEndAction()
}
},
fullScreenChangeAction(e) {
console.log(e)
},
changeScreenTap() {
this.videoCtx.requestFullScreen({ direction: 90 })
},
// 跳转到某个点
seekToPoint(time){
console.log('跳转到时间:'+time)
videoCtx.seek(time)
}
}
})
代码中,主要实现了对video控件的进度条的拖拽进行了控制,如果在用户将进度条拖拽到还未观看过的视频位置,那么视频将会跳回到用户观看过的最大位置,并提示用户不能进装操作。
由于系统未提供video进度条拖拽的事件监听接口,我们只能“绕个弯”实现该功能。
实现的原理就是通过监听video控件开放的bindtimeupdate播放过程中的进度监听事件,我们通过监听进度条当前的进度与上一次回调的进度进行比较,如果两者之差大于3,便视为用户进行了拖拽操作,具体的代码,查看上述的timeUpdate(e)与endAction(e)事件中的相关代码。
起初,原本想自定义控制器来实现监听视频进度条拖拽的相关功能,但通过实践,我们发现,在video上的cover-view中无法嵌套系统提供的slider组件,同时在video控件上,无法进行自定义拖拽事件的监听(开发工具上可以监听,真机上无法进行监听,具体的原因还需考察),所以目前只能通过该方法实现控制拖拽进度条的操作。