自己写的播放器,记录一下
player.wxml
<view class="player-container">
<video id="myVideo" bindtap="triggerControls" class="my-video" direction
show-progress="{{true}}"
show-fullscreen-btn="{{true}}"
show-play-btn="{{true}}"
enable-play-gesture="{{true}}"
vslide-gesture-in-fullscreen="{{true}}"
show-center-play-btn="{{false}}" bindplay="play" bindpause="pause"
bindended="ended" bindtimeupdate="timeUpdate"
bindfullscreenchange="fullScreenChange" muted="{{mutedFlag}}"
controls="{{controlsFlag}}" src="{{filePath}}">
<cover-image class="prev {{fullScreenFlag?'big':'sm'}}" bindtap="prev" wx:if="{{curIndex != 0 && cusControlsFlag}}" src="../../utils/image/pre.png">cover-image>
<cover-image class="next {{fullScreenFlag?'big':'sm'}}" bindtap="next" wx:if="{{curIndex != totalVideoCount-1 && cusControlsFlag}}" src="../../utils/image/next.png">cover-image>
<cover-view class="bottom-notice {{fullScreenFlag?'big':'sm'}}" wx:if="{{cusControlsFlag}}">
<cover-view class="bottom-section {{fullScreenFlag?'big':'sm'}}">
{{curIndex+1}}/{{totalVideoCount}}
cover-view>
<cover-view class="bottom-title {{fullScreenFlag?'big':'sm'}}">
{{fileList[curIndex].title}}
cover-view>
cover-view>
<button class="detail-btn {{fullScreenFlag?'big':'sm'}}" wx:if="{{cusControlsFlag}}" bindtap="showDetail">查看详情button>
video>
view>
player.wxss
page{
width:100%;
height:100%;
}
.player-container{
width:100%;
height:100%;
background-color:rgba(0,0,0,0.8);
}
.my-video{
position:absolute;
width:100%;
top:50%;
transform:translateY(-50%);
}
/* .cover-view-box{
width:100%;
height:100%;
position:relative;
}
.cover-view-box.paused{
background-color:rgba(14,14,18,0.8);
}
.progress-box{
height:10rpx;
background:#ffffff;
}
.progress-box .progress-bar{
height:10rpx;
background:#FC9541;
}
.time-detail-btn{
width:100%;
height:80rpx;
position:relative;
}
.time-detail-btn .time-text{
position: absolute;
left: 30rpx;
top: 22rpx;
display: inline-block;
font-size: 36rpx;
height: 36rpx;
line-height: 36rpx;
color: #60606A;
}
.time-detail-btn .detail-btn{
position:absolute;
right:0rpx;
top:22rpx;
display:inline-block;
width:120rpx;
height:36rpx;
font-size:20rpx;
line-height:36rpx;
border-top-right-radius:0;
border-bottom-right-radius:0;
border-top-left-radius:18rpx;
border-bottom-left-radius:18rpx;
background-color:#5F5F69;
color:#ffffff;
}
.center-btns{
width:100%;
height:120rpx;
position:absolute;
top:50%;
margin-top:-60rpx;
}
.center-btns .prev-btn,.center-btns .next-btn{
width:60rpx;
height:120rpx;
}
.center-btns .prev-btn{
position:absolute;
left:60rpx;
}
.center-btns .next-btn{
position:absolute;
right:60rpx;
}
.center-btns-paused{
width:100%;
height:180rpx;
position:absolute;
top:50%;
margin-top:-90rpx;
text-align:center;
}
.center-btns-paused .stop-btn-box,.center-btns-paused .play-btn-box{
display:inline-block;
width:180rpx;
height:180rpx;
text-align:center;
}
.center-btns-paused .stop-btn-box .stop-btn,.center-btns-paused .play-btn-box .play-btn{
width:120rpx;
height:120rpx;
margin: 0 auto;
}
.center-btns-paused .stop-btn-box .stop-tt,.center-btns-paused .play-btn-box .play-tt{
font-size:36rpx;
line-height:40rpx;
color:#ffffff;
margin: 0 auto;
}
.bottom{
width:100%;
height:60px;
position: absolute;
bottom:15rpx;
}
.bottom .bottom-left{
position:absolute;
left:30rpx;
width:50%;
height:60px;
}
.bottom .bottom-left .left-progress{
font-size:36rpx;
line-height:30px;
color:#ffffff;
}
.bottom .bottom-left .left-title{
font-size:36rpx;
line-height:30px;
color:#ffffff;
}
.bottom .bottom-right{
position:absolute;
right:30rpx;
width:30%;
height:60px;
}
.bottom .bottom-right .pause-btn{
width:60px;
height:60px;
position: absolute;
right: 0;
}
.out-box{
width:60px;
height:60px;
margin:0 auto ;
position:absolute;
top:0;
right:0;
transform:rotate(-90deg);
}
.right-square,.left-square{
width:30px;
height:60px;
position:absolute;
top:0;
overflow:hidden;
}
.right-square{
right:0;
}
.left-square{
left:0;
}
.circle{
box-sizing: border-box;
width:60px;
height:60px;
border:10rpx solid transparent;
border-radius:50%;
position:absolute;
top:0;
transform: rotate(-135deg);
}
.right-circle{
border-top:10rpx solid #ff0;
border-right:10rpx solid #ff0;
right:0;
transform: rotate(-135deg);
}
.left-circle{
border-bottom:10rpx solid #ff0;
border-left:10rpx solid #ff0;
left:0;
transform: rotate(-135deg);
} */
.detail-btn.big{
position:absolute;
right:0rpx;
top:30rpx;
display:inline-block;
width:180rpx;
height:60rpx;
font-size:30rpx;
line-height:60rpx;
border-top-right-radius:0;
border-bottom-right-radius:0;
border-top-left-radius:30rpx;
border-bottom-left-radius:30rpx;
background-color:#5F5F69;
color:#ffffff;
}
.detail-btn.sm{
position:absolute;
right:0rpx;
top:15rpx;
display:inline-block;
width:120rpx;
height:40rpx;
font-size:16rpx;
line-height:40rpx;
border-top-right-radius:0;
border-bottom-right-radius:0;
border-top-left-radius:20rpx;
border-bottom-left-radius:20rpx;
background-color:#5F5F69;
color:#ffffff;
}
.prev.big,.next.big{
width:57rpx;
height:87rpx;
position:absolute;
top:50%;
margin-top:-43rpx;
}
.prev.sm,.next.sm{
width:38rpx;
height:58rpx;
position:absolute;
top:50%;
margin-top:-29rpx;
}
.prev.big{
left:60rpx;
}
.next.big{
right:60rpx;
}
.prev.sm{
left:30rpx;
}
.next.sm{
right:30rpx;
}
.bottom-notice.sm{
position:absolute;
width:100%;
height:90rpx;
bottom:80rpx;
left:15rpx;
font-size:20rpx;
line-height:30rpx;
color:#ffffff;
}
.bottom-notice.big{
position:absolute;
width:100%;
height:180rpx;
bottom:100rpx;
left:30rpx;
font-size:40rpx;
line-height:60rpx;
color:#ffffff;
}
.bottom-section.big{
font-size:80rpx;
line-height:120rpx;
}
.bottom-section.sm{
font-size:40rpx;
line-height:60rpx;
}
.locking-screed.big{
position:absolute;
width:120rpx;
height:120rpx;
top:60rpx;
left:30rpx;
font-size:60rpx;
line-height:120rpx;
color:#ffffff;
}
.locking-screed.sm{
position:absolute;
width:60rpx;
height:60rpx;
top:15rpx;
left:15rpx;
font-size:30rpx;
line-height:60rpx;
color:#ffffff;
}
player.js
let app = getApp();
var urlGlobal = app.globalData.host;
Page({
/**
* 页面的初始数据
*/
data: {
progress: 0, //下载进度
percent: 0, //样式百分比
flag: false, //是否展示下载进度
fileList: [], //本地文件list
filePath: '', //当前播放文件路径
mutedFlag: false, //是否静音
curIndex: 0, //当前播放视频对应fileList的下标
totalVideoCount: 0, //视频总数
controlsFlag: true, //是否展示控制按钮
cusControlsFlag: true, //自定义按钮是否展示
playFlag: false, //是否播放 true-播放,false-暂停
Timer: null, //定时器ID,计算xyz加速度屏幕变化延迟
countDownStr: '0:00', //当前播放进度展示
timePercent: 0, //播放进度的百分比,控制进度条样式的
leftDeg: -135, //圆形进度条css控制
rightDeg: -135, //圆形进度条css控制
pFlag: true, //控制圆形进度条左右方块的动画执行
fullScreenFlag: false, //是否全屏
accelerometerFlag: true, //开启页面加速度状态记录
totalCount: 0, //总视频数
train_time: 0, //看视频时长,暂停除外,只记录播放时长
trainTimer: null //记录看视频时长的定时器ID
},
//下载视频到本地
downLoadFile() {
this.setData({
flag: true
})
let downLoadTask = wx.downloadFile({
url: 'https://chongcheng.oss-cn-beijing.aliyuncs.com/video/05efe16f1e0e77d238dd3e1028f69f08.mp4?OSSAccessKeyId=LTAIm8PZwyv8Jz7K&Expires=1568777767&Signature=m27xVzEM4BViH%2BL9Zucm7Yb%2FG6o%3D',
success(res) {
// 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
if (res.statusCode === 200) {
wx.saveFile({
tempFilePath: res.tempFilePath,
success(res) {
let savedFilePath = res.savedFilePath
},
fail(err) {
}
})
}
}
})
downLoadTask.onProgressUpdate((res) => {
//
let totalSize = res.totalBytesExpectedToWrite;
let curSize = res.totalBytesWritten;
let percent = Math.ceil(curSize / totalSize * 10000) / 100;
this.setData({
progress: res.progress,
percent
})
})
},
//设置当前播放视频
setFilePath(e) {
let filePath = this.data.fileList[e.currentTarget.dataset.index].filePath;
this.setData({
filePath,
curIndex: e.currentTarget.dataset.index
})
},
//展示自定义控制样式
showControls() {
if (this.data.Timer) {
clearTimeout(this.data.Timer);
this.setData({
Timer: null
});
}
let Timer = setTimeout(() => {
this.setData({
controlsFlag: false
});
}, 3000)
this.setData({
controlsFlag: true,
Timer
});
},
//同上
triggerControls() {
let flag = !this.data.cusControlsFlag;
if (flag) {
if (this.data.Timer) clearTimeout(this.data.Timer)
let Timer = setTimeout(() => {
this.setData({
cusControlsFlag: false
});
}, 3000);
this.setData({
Timer
});
}
this.setData({
cusControlsFlag: flag,
})
},
//上一个
prev() {
// this.myVideo.stop();
let curIndex = this.data.curIndex - 1;
let filePath = this.data.fileList[curIndex].filePath;
this.setData({
curIndex,
filePath
});
this.getFileInfo();
this.initData();
setTimeout(() => {
this.myVideo.play();
}, 100)
},
//下一个
next() {
// this.myVideo.stop();
let curIndex = this.data.curIndex + 1;
if (curIndex >= this.data.fileList.length) {
this.toComplete();
return;
}
let filePath = this.data.fileList[curIndex].filePath;
this.setData({
curIndex,
filePath
});
this.getFileInfo();
this.initData();
setTimeout(() => {
this.myVideo.play();
}, 100)
},
//播放
toPlay() {
if (this.data.nextTimer) {
clearTimeout(this.data.nextTimer);
this.setData({
nextTimer: null
})
}
this.myVideo.play();
},
//暂停
toPause() {
this.myVideo.pause();
this.sendTrainTime();
},
//停止
toStop() {
// this.myVideo.stop();
wx.navigateBack();
},
//全屏
inFullScreen(direction) {
this.myVideo.requestFullScreen({ direction });
},
//退出全屏
outFullScreen() {
this.myVideo.exitFullScreen();
},
//播放自动触发
play(e) {
console.log('play');
if (this.data.trainTimer) {
clearInterval(this.data.trainTimer);
this.setData({
trainTimer: null
})
}
let trainTimer = setInterval(() => {
let train_time = this.data.train_time;
train_time += 1;
this.setData({
train_time
})
}, 1000);
this.setData({
trainTimer,
playFlag: true
})
},
//暂停自动触发
pause(e) {
console.log('pause');
if (this.data.trainTimer) {
clearInterval(this.data.trainTimer);
this.setData({
trainTimer: null
})
}
this.sendTrainTime();
this.setData({
playFlag: false,
train_time: 0
})
},
//结束自动触发
ended(e) {
console.log('ended');
var that = this;
if (this.data.trainTimer) {
clearInterval(this.data.trainTimer);
this.setData({
trainTimer: null
})
}
this.sendTrainTime();
that.setData({
playFlag: false,
controlsFlag: true,
train_time: 0
});
let nextTimer = setTimeout(() => {
that.next();
}, 1000)
that.setData({
nextTimer
})
that.initData();
},
/**视频播放中随时触发**/
timeUpdate(e) {
let detail = e.detail;
/**当前播放进度 */
let nowTime = detail.currentTime;
let totalTime = detail.duration;
let remainderTime = totalTime - nowTime;
let str = this.formatTime(remainderTime);
let timePercent = Math.ceil(nowTime / totalTime * 100);
let rightDeg, leftDeg;
if (timePercent <= 50) {
this.setData({
pFlag: true
})
rightDeg = Math.ceil(180 / 50) * timePercent + (-135);
rightDeg = rightDeg > 45 ? 45 : rightDeg;
this.setData({
rightDeg
})
} else {
this.setData({
pFlag: false
})
leftDeg = Math.ceil(180 / 50) * (timePercent - 50) + (-135);
leftDeg = leftDeg > 45 ? 45 : leftDeg;
this.setData({
leftDeg
})
}
let flag = this.data.pFlag;
if (flag) {
rightDeg = this.data.rightDeg;
} else {
leftDeg = this.data.leftDeg;
}
if (flag) {
} else {
}
nowTime = Math.floor(nowTime);
this.setData({
countDownStr: str,
timePercent,
// train_time:nowTime,
})
},
//全屏状态变化触发
fullScreenChange(e) {
if (!e.detail.fullScreen) {
// wx.navigateBack()
setTimeout(() => {
this.setData({
fullScreenFlag: false
})
}, 500)
} else {
setTimeout(() => {
this.setData({
fullScreenFlag: true
})
}, 500)
}
},
//初始化参数
initData() {
let leftDeg = -135,
rightDeg = -135,
pFlag = true;
this.setData({
leftDeg, rightDeg, pFlag
})
},
//获取文件信息 无用
getFileInfo() {
wx.getSavedFileInfo({
filePath: this.data.filePath,
success: (res) => {
},
fail: (err) => {
}
})
},
//毫秒数格式化
formatTime(second) {
let diff = parseInt(second * 1000);
let str = '';
// 毫秒化天
let d = Math.floor(diff / (24 * 3600 * 1000));
if (d > 0) {
// str += d + '天'
}
// 毫秒化小时
let rh = diff % (24 * 3600 * 1000);
let h = Math.floor(rh / (3600 * 1000));
h = h < 10 ? '0' + h : h;
// if (h > 0 || d > 0) {
// str += h + ':'
// } else {
// str += '00:'
// }
// 毫秒化分钟
let rm = rh % (3600 * 1000);
let m = Math.floor(rm / (60 * 1000));
m = m < 10 ? '0' + m : m;
if (m > 0 || d > 0 || h > 0) {
str += m + ':'
} else {
str += '00:'
}
// 毫秒化秒
let rs = rm % (60 * 1000);
let s = Math.round(rs / 1000);
s = s < 10 ? '0' + s : s;
if (s > 0 || d > 0 || h > 0 || m > 0) {
str += s
} else {
str += '00'
}
return str;
},
/**
* 开启计算页面加速度,调整页面朝向是否全屏播放
*/
startAccelerometer() {
this.setData({
accelerometerFlag: true
})
let lastState = this.data.fullScreenFlag ? 1 : 0;
let lastTime = Date.now();
// wx.startAccelerometer({
// success:()=>{
wx.onAccelerometerChange((res) => {
const now = Date.now();
// 500ms检测一次
if (now - lastTime < 500) {
return;
}
lastTime = now;
let nowState;
// 57.3 = 180 / Math.PI
const Roll = Math.atan2(-res.x, Math.sqrt(res.y * res.y + res.z * res.z)) * 57.3;
const Pitch = Math.atan2(res.y, res.z) * 57.3;
//
// 横屏状态
//
//
if (Roll > 50) {
if ((Pitch > -180 && Pitch < -60) || (Pitch > 130)) {
nowState = 1;
} else {
nowState = lastState;
}
} else if ((Roll > 0 && Roll < 30) || (Roll < 0 && Roll > -30)) {
let absPitch = Math.abs(Pitch);
// 如果手机平躺,保持原状态不变,40容错率
if ((absPitch > 140 || absPitch < 40)) {
nowState = lastState;
} else if (Pitch < 0) { /*收集竖向正立的情况*/
nowState = 0;
} else {
nowState = lastState;
}
} else if (Roll < -50) {
if ((Pitch > -180 && Pitch < -60) || (Pitch > 130)) {
nowState = 2;
} else {
nowState = lastState;
}
} else {
nowState = lastState;
}
// 状态变化时,触发
if (nowState !== lastState) {
lastState = nowState;
if (nowState === 1) {
clearTimeout(this.data.Timer);
this.setData({
Timer: null
})
let Timer = setTimeout(() => {
if (!this.data.fullScreenFlag)
this.inFullScreen(90);
}, 500)
this.setData({
Timer
})
} else if (nowState === 2) {
clearTimeout(this.data.Timer);
this.setData({
Timer: null
})
let Timer = setTimeout(() => {
if (!this.data.fullScreenFlag)
this.inFullScreen(-90);
}, 500)
this.setData({
Timer
})
} else {
clearTimeout(this.data.Timer);
this.setData({
Timer: null
})
let Timer = setTimeout(() => {
if (this.data.fullScreenFlag)
this.outFullScreen();
}, 500)
this.setData({
Timer
})
}
}
});
// }
// });
},
/**
* 停止页面加速度计算,锁定屏幕
*/
stopAccelerometer() {
this.setData({
accelerometerFlag: false
})
wx.offAccelerometerChange((res) => {
});
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
let that = this;
wx.getStorage({
key: 'catch_lesson',
success: (res) => {
let info = JSON.parse(res.data);
let list = info.lesson_info;
let actIndex = wx.getStorageSync('actIndex');
let curIndex = actIndex ? actIndex : 0;
that.setData({
totalVideoCount: list.length,
fileList: list,
filePath: list[curIndex].filePath,
curIndex
})
}
})
},
drawCircle: function () {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
this.myVideo = wx.createVideoContext('myVideo');
this.toPlay();
let Timer = setTimeout(() => {
this.setData({
cusControlsFlag: false
})
}, 3000);
this.setData({
Timer
})
this.startAccelerometer();
},
// 页面卸载
onUnload() {
// console.log('页面返回',this.data.train_time);
if (this.data.trainTimer) {
clearInterval(this.data.trainTimer);
this.setData({
trainTimer: null
})
}
this.sendTrainTime();
this.setData({
train_time: 0
})
},
onHide() {
},
onShow() {
},
showDetail() {
wx.navigateTo({
url: "/recover/vid/actXiang/actXiang"
})
},
toComplete() {
wx.navigateTo({
url: '/recover/vid/vidcomplete/vidcomplete'
})
},
sendTrainTime() {
let that = this;
let train_time = that.data.train_time;
/**传送记录课程观看 */
wx.getStorage({
key: 'openid',
success(res) {
var openid = res.data;
wx.getStorage({
key: 'keId',
success(ress) {
var keId = ress.data;
wx.request({
url: urlGlobal + 'Train/train_time_statistics',
method: 'post',
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: { openid: openid, lesson_id: keId, train_time },
success: function (resut) {
console.log('播放结束', resut);
}
})
}
})
}
})
}
})
提示:
这个播放器改动好几次,所以中间有两个版本,注释掉的就是另外一个版本的,至于JS页面的多余函数和定义的变量,用不到的自行删除,我在这边只自己记录一下,方便以后其他项目中用到直接拿来改改就用