video
视频
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
src | String | 是 | 要播放视频的资源地址,支持网络路径、本地路径 | ||
duration | Number | 否 | 指定视频时长 | ||
controls | Boolean | true | 否 | 是否显示默认播放控件(播放/暂停按钮、播放进度、时间) | |
autoplay | Boolean | false | 否 | 是否自动播放 | |
loop | Boolean | false | 否 | 是否循环播放 | |
muted | Boolean | false | 否 | 是否静音播放 | |
initial-time | Number | 0 | 否 | 指定视频初始播放位置 | |
show-progress | Boolean | true | 否 | 是否显示进度条 | |
show-fullscreen-btn | Boolean | true | 否 | 是否显示全屏按钮 | |
show-play-btn | Boolean | true | 否 | 是否显示视频底部控制栏的播放按钮 | |
show-center-play-btn | Boolean | true | 否 | 是否显示视频中间的播放按钮 | |
enable-progress-gesture | Boolean | true | 否 | 是否开启控制进度的手势 | |
object-fit | String | contain | 否 | 当视频大小与 video 容器大小不一致时,视频的表现形式 | |
poster | String | 否 | 视频封面的图片资源地址, 支持网络路径、本地路径。若 controls 属性值为 false 则设置 poster 无效 | ||
show-mute-btn | Boolean | false | 否 | 是否显示静音按钮 | |
play-btn-position | String | bottom | 否 | 播放按钮的位置 | |
enable-play-gesture | Boolean | false | 否 | 是否开启播放手势,即双击切换播放/暂停 | |
bindplay | EventHandle | 否 | 当开始/继续播放时触发play事件 | ||
bindpause | EventHandle | 否 | 当暂停播放时触发 pause 事件 | ||
bindended | EventHandle | 否 | 当播放到末尾时触发 ended 事件 | ||
bindtimeupdate | EventHandle | 否 | 播放进度变化时触发,event.detail = {currentTime, duration} 。 | ||
bindfullscreenchange | EventHandle | 否 | 视频进入和退出全屏时触发,event.detail = {fullScreen} | ||
bindwaiting | EventHandle | 否 | 视频出现缓冲时触发 | ||
binderror | EventHandle | 否 | 视频播放出错时触发 | ||
bindprogress | EventHandle | 否 | 加载进度变化时触发,只支持一段加载。event.detail = {buffered},百分比 | ||
bindloadedmetadata | EventHandle | 否 | 视频元数据加载完成时触发。event.detail = {width, height, duration} | ||
bindcontrolstoggle | EventHandle | 否 | 切换 controls 显示隐藏时触发。event.detail = {show} | ||
bindseekcomplete | EventHandler | 否 | seek 完成时触发 (position 单位 ms) |
object-fit 的合法值
值 | 说明 | 最低版本 |
---|---|---|
contain | 包含 | |
fill | 填充 | |
cover | 覆盖 |
play-btn-position 的合法值
值 | 说明 | 最低版本 |
---|---|---|
bottom | controls bar上 | |
center | 视频中间 |
Tips:
- 视频格式参考各系统对 Html Video 标签的支持
- 使用本地路径时,路径名需要有后缀名。
示例代码:
<view class="container">
<view class="statement">视频。</view>
<video id="video"
src="{{src}}"
duration="{{duration}}"
controls="{{controls}}"
autoplay="{{autoplay}}"
loop="{{loop}}"
muted="{{muted}}"
show-progress="{{showProgress}}"
show-fullscreen-btn="{{showFullscreenBtn}}"
show-play-btn="{{showPlayBtn}}"
show-center-play-btn="{{showCenterPlayBtn}}"
enable-progress-gesture="{{enableProgressGesture}}"
object-fit="{{objectFit}}"
poster="{{poster}}"
show-mute-btn="{{showMuteBtn}}"
play-btn-position="{{playBtnPosition ? 'center' : 'bottom'}}"
enable-play-gesture="{{enablePlayGesture}}"
bindplay="bindevent"
bindpause="bindevent"
bindended="bindevent"
bindtimeupdate="bindevent"
bindfullscreenchange="bindevent"
bindwaiting="bindevent"
bindprogress="bindevent"
bindloadedmetadata="bindevent"
bindcontrolstoggle="bindevent"
bindseekcomplete="bindevent"
binderror="bindevent"
></video>
<view>
<view mc:for="{{videoList}}">{{(index + 1) + '. ' + item.title}}</view>
</view>
<view class="buttonContainer">
<button size="mini" mc:for="{{methods}}" bindtap="{{item.method}}">{{item.desc}}</button>
</view>
<radio-group bindchange="objectFitChanged">
<view class="cssname">object-fit</view>
<radio value="contain" checked name="objectFit">contain:包含</radio>
<radio value="fill" name="objectFit">fill:填充</radio>
<radio value="cover" name="objectFit">cover:覆盖</radio>
</radio-group>
<block mc:for="{{properties}}">
<view class="cssname">{{item.name + ': ' + item.desc}}</view>
<checkbox bindtap="propValueChanged" data-index="{{index}}" checked="{{item.value}}" value="{{item.prop}}">{{item.valueDesc}}</checkbox>
</block>
<block mc:for="{{events}}">
<view class="cssname">{{item.name + ":" + item.desc}}, 参数event.detail</view>
<text space="nbsp" user-select="true" class="scrollDetail">{{item.detail || ''}}</text>
</block>
</view>
// pages/component/pages/video/video.js
Page({
data: {
videoList: [
{title: 'video1', src :'https://test/video1.mp4', poster: ''},
{title: 'video2', src :'http://test/video2.m3u8', poster: '/assets/images/video_poster.jpg'},
{title: 'travel', src :'../../../../../assets/media/travel.mp4', poster: ''}
],
events:[
{"name" : "bindplay", "desc" : "当开始/继续播放时触发"},
{"name" : "bindpause", "desc" : "当暂停播放时触发"},
{"name" : "bindended", "desc" : "当播放到末尾时触发"},
{"name" : "bindtimeupdate", "desc" : "播放进度变化时触发"},
{"name" : "bindfullscreenchange", "desc" : "视频进入和退出全屏时触发"},
{"name" : "bindwaiting", "desc" : "视频出现缓冲时触发"},
{"name" : "bindprogress", "desc" : "加载进度变化时触发"},
{"name" : "bindloadedmetadata", "desc" : "视频元数据加载完成时触发"},
{"name" : "bindcontrolstoggle", "desc" : "切换 controls 显示隐藏时触发"},
{"name" : "bindseekcomplete", "desc" : "seek 完成时触发"},
{"name" : "binderror", "desc" : "视频播放出错时触发"}
],
properties: [
{"prop" : "controls", "name" : "controls", "desc": "是否显示默认播放控件", value: true, valueDesc: '显示'},
{"prop" : "autoplay", "name" : "autoplay", "desc": "是否自动播放", value: true, valueDesc: '是'},
{"prop" : "loop", "name" : "loop", "desc": "是否循环播放", value: false, valueDesc: '循环播放'},
{"prop" : "muted", "name" : "muted", "desc": "是否静音播放", value: false, valueDesc: '静音'},
{"prop" : "showProgress", "name" : "show-progress", "desc": "是否显示进度条", value: true, valueDesc: '显示'},
{"prop" : "showFullscreenBtn", "name" : "show-fullscreen-btn", "desc": "是否显示全屏按钮", value: true, valueDesc: '显示'},
{"prop" : "showPlayBtn", "name" : "show-play-btn", "desc": "是否显示控制栏播放按钮", value: true, valueDesc: '显示'},
{"prop" : "showCenterPlayBtn", "name" : "show-center-play-btn", "desc": "是否显示视频中间播放按钮", value: true, valueDesc: '显示'},
{"prop" : "enableProgressGesture", "name" : "enable-progress-gesture", "desc": "是否开启控制进度的手势", value: true, valueDesc: '开启'},
{"prop" : "showMuteBtn", "name" : "show-mute-btn", "desc": "是否显示静音按钮", value: false, valueDesc: '显示'},
{"prop" : "playBtnPosition", "name" : "play-btn-position", "desc": "播放按钮位置", value: false, valueDesc: 'center'},
{"prop" : "enablePlayGesture", "name" : "enable-play-gesture", "desc": "是否开启双击切换播放/暂停", value: false, valueDesc: '开启'},
],
methods:[
{method: 'play', desc: '播放视频'},
{method: 'pause', desc: '暂停视频'},
{method: 'stop', desc: '停止视频'},
{method: 'seek', desc: '跳转到10秒'},
{method: 'next', desc: '下一个'},
{method: 'playbackRate', desc: '1.5倍播放'},
{method: 'resetRate', desc: '1.0倍播放'},
{method: 'requestFullScreen', desc: '进入全屏(3秒退出)'}
],
currentIndex: 0,
controls: true,
pictureInPictureMode: ["pop", "push"]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var data = {}
for(var i = 0; i < this.data.properties.length; i++){
data[this.data.properties[i].prop] = this.data.properties[i].value
}
data.danmuList = [];
for(var i = 0; i < 20; i++){
data.danmuList.push({
text : '第 ' + (i + 1) + 's 出现的弹幕1',
color: '#fff',
time: i + 1
})
}
for(var i = 0; i < 20; i++){
data.danmuList.push({
text : '第 ' + (i + 1) + 's 出现的弹幕2',
color: '#ff0000',
time: i + 1
})
}
this.setData(data);
},
onReady: function(){
this.videoCtx = mc.createVideoContext('video');
console.log(this.videoCtx)
this.setCurrent(this.data.currentIndex, false);
},
next: function() {
this.data.currentIndex += 1;
if(this.data.currentIndex >= this.data.videoList.length){
this.data.currentIndex = 0;
}
this.setCurrent(this.data.currentIndex, false);
},
setCurrent: function(index, p){
var data = this.data.videoList[index];
this.setData(data)
if(p){
this.play();
}
},
play: function(e){
mc.createSelectorQuery().select('#video').context((res) => {
res.context.play()
}).exec();
},
pause: function(e){
this.videoCtx.pause();
},
stop: function(e){
this.videoCtx.stop();
},
seek: function(e){
this.videoCtx.seek(10);
},
playbackRate: function(e){
this.videoCtx.playbackRate(1.5);
},
resetRate: function(e){
this.videoCtx.playbackRate(1.0);
},
requestFullScreen: function(e){
this.videoCtx.requestFullScreen();
var _this = this;
setTimeout(function(res){
_this.videoCtx.exitFullScreen()
}, 3000);
},
objectFitChanged: function(e){
this.setData({
objectFit: e.detail.value
})
},
propValueChanged: function(e){
var item = this.data.properties[e.currentTarget.dataset.index];
item.value = !item.value;
var data = {};
data[item.prop] = item.value;
this.setData(data);
},
bindevent: function(e){
var eventName = 'bind' + e.type;
var index = 0;
for(var i = 0; i < this.data.events.length; i++){
if(this.data.events[i].name == eventName){
index = i;
break;
}
}
var eventIndex = 'events[' + index + '].detail';
this.setData({
[eventIndex] : JSON.stringify(e, null, 2)
})
}
})