微信小程序自定义播放器实现左右箭头切换视频,根据手机横屏竖屏自动全屏和退出全屏

自己写的播放器,记录一下
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页面的多余函数和定义的变量,用不到的自行删除,我在这边只自己记录一下,方便以后其他项目中用到直接拿来改改就用

你可能感兴趣的:(微信小程序)