如何快速开发一个自定义的视频播放器(3)——方法实现

如何快速开发一个自定义的视频播放器(3)——方法实现

技术博客 admin 141 浏览

方法实现

本篇主要介绍上篇定义的所有方法的实现,写方法实际是逻辑分解的过程,当我们把我们的逻辑分解的足够小的时候,其实所有的方法都很容易实现。这里推荐一本书《福格行为模型》,当人们遇到复杂的事情的时候,一开始是抗拒不愿意去做的,但是当我们把事情分解到足够简单的多件事情时,每完成一个简单事情都能够正向鼓励自己,这才是实现复杂目标和事物的正确方法。事情的道理都是一样的,编码也一样,逻辑分解到足够小的时候,任何复杂的算法逻辑都很简单。

  1. 初始化。根据我们需求,初始化我们的播放去需要对视频的几个事件进行监听:

1.onloadedmetadata 监听加载metadata信息 获取duration信息
2.ontimeupdate 监听播放进度的事件 主要用来进度条控制
3.onpause 视频暂停监听 进行部分视频状态控制
4.onplay 视频开启播放监听

同时初始化视频的相关信息,这里我们做出如下实现:

javascript
复制代码
LoadVideo(video) { // 监听加载metadata信息 获取duration信息 video.onloadedmetadata = () => { this.video.duration = video.duration this.video.durationString = this.GetTime(video.duration) } // 监听播放进度的事件 主要用来进度条控制 video.ontimeupdate = () => { // 获取currentTime var ctime = +video.currentTime.toFixed(2) this.video.currentTime = ctime // 更新currentTime字符串 this.video.currentTimeString = this.GetTime(ctime) // 更新当前进度百分比 currentTime/totalTime*100 this.video.progress = (ctime * 100) / this.video.duration // 进度条宽度设置 this.$refs.progressCurrentLine.style.width = `${this.video.progress}%` // indicator的偏移位置 由于指示器是一个圆,因此需要计算指示器圆心的位置 currentTime/totalTime*进度条总宽度,因为开始时圆心在起点,因此再减去indicator的半径即可得到偏移位置 var transformx = (ctime * this.$refs.progress.offsetWidth) / this.video.duration - this.$refs.indicator.offsetWidth / 2 // 这里使用transform而不是用left后面会解释 this.$refs.indicator.style.transform = `translateY(-50%) translateX(${transformx}px)` // 判断视频结束,冷知识,video没有结束监听事件 if (video.currentTime >= this.video.duration) { this.video.status = 'stop' } } // waiting监听 可能有用 有些环境没有用 video.onwaiting = () => { // 播放状态下才会触发waiting事件 this.video.status = 'wait' } // 视频资源加载到足够播放事件监听 video.oncanplay = () => { // 如果是等待状态,说明加载好就要进行播放。 if (this.video.status === 'wait') { this.video.status = 'play' } } // 视频暂停监听 video.onpause = () => { this.video.status = 'pause' this.video.starting = false // 是否展示start play btn 正常视频结束才展示,拖动indicator时的视频暂停并不展示 if (this.video.isSlider == false && this.video.status !== 'stop') { this.showStartPlay = true } // 暂停时展示control pannel,且不隐藏 this.showPannel = true } // 视频开启播放监听 video.onplay = () => { console.log('start play') this.video.starting = true this.ShowControls() this.video.status = 'play' this.showStartPlay = false } this.video.target = video }
  1. 播放事件,这个比较简单,当视频暂停时播放,当视频播放时暂停
javascript
复制代码
PlayVideo() { // this.video.target.paused 可以获取到视频的暂停状态 if (this.video.target.paused) { this.video.target.play() } else { this.video.target.pause() } }
  1. 全屏事件,全屏事件不同浏览器提供的api有所差别需要进行兼容性处理
javascript
复制代码
SetFullScreen() { const video = this.video.target if (video.requestFullscreen) { video.requestFullscreen() } else if (video.mozRequestFullScreen) { /* Firefox */ video.mozRequestFullScreen() } else if (video.webkitRequestFullscreen) { /* Chrome, Safari 和 Opera */ video.webkitRequestFullscreen() } else if (video.msRequestFullscreen) { /* IE/Edge */ video.msRequestFullscreen() } }
  1. 控制control pannel展示事件,这里有两个逻辑需求,一个是基本的展示后隐藏需求,一个是在播放过程种可以随时点击control mask使得control pannel即时展示和隐藏,对应两个方法
javascript
复制代码
// 基本的control pannel控制 time为默认展示时间 ShowControls(time = 2000) { this.video.showTime = time this.showPannel = true // 基本防抖 if (this.video.showTimer) { clearTimeout(this.video.showTimer) } // 一段时间后隐藏 this.video.showTimer = setTimeout(() => { this.showPannel = false }, this.video.showTime) }, // 播放过程种随时点击control mask使得control pannel即时展示和隐藏 ShowControl() { if (this.video.showPannel === true) { if (this.video.showTimer) { clearTimeout(this.video.showTimer) } // 如果control pannel正在展示,则立即隐藏 this.video.showPannel = false } else { this.ShowControls(3000) } },
  1. 点击seek实现,点击控制调计算点击位置的currentTime,seek这个时刻即可,因为我们在ontimeupdate已经实现了进度条展示和indicataor的定位逻辑,因此这里我们只需计算出currentTime即可
javascript
复制代码
Seek(e) { this.$nextTick(() => { // 计算方法比较简单根据offsetX和进度调的偏移来计算 this.video.target.currentTime = (e.offsetX / this.$refs.progress.offsetWidth) * this.video.duration Ï }) }
  1. indicator指示器拖动,由于我们仅期望本demo运行在移动端,因此我们实现touchstart、touchmove、touchend即可,基本的逻辑就是:
  1. 按下indicator时刻暂停视频播放同时纪录拖动开始位置,需要注意的是我们的indicator是一个圆,我们需要精确计算到实际的滚动范围,因此我们在按下手指的时候,同时纪录一下indicator和手指距离的实际偏移
  2. 拖动过程种不断计算我们的滚动条宽度和indicator的偏移,实际上简单的做法是我们只需要计算时间的变化即可(取巧方法,不用进行复杂思考),宽度和indicator的偏移我们可以根据时间也就是currentTime转换得到,这个已经在ontimeupdate里面实现。
  3. 拖动结束,seek并播放视频

具体代码

javascript
复制代码
TouchStart(e) { // 纪录拖动状态 this.video.isSlider = true this.video.target.pause() var pageX = e.touches[0].pageX this.video.istartX = pageX // 这里通过则匹配获取indicator的偏移,因为不是left而是translateX var transformX = this.$refs.indicator.style.transform.match( /translateX\((.*?)px\)/ )[1] // 计算实际偏移 this.video.istartOffsetX = pageX - (+transformX + this.$refs.progress.offsetLeft) }, TouchMove(e) { this.video.target.pause() var pageX = e.touches[0].pageX // 计算手指x轴偏移距离 var idistance = pageX - this.video.istartX // 判断偏移距离对应的偏移时间 var moveTime = (idistance / this.$refs.progress.offsetWidth) * this.video.duration // set left 计算实际的left距离 var left = this.video.istartX + idistance - this.video.istartOffsetX // indicator的x轴的最小偏移和最大偏移,拖动不可超出时间轴 // 最大偏移=轴左偏移+轴宽度+指示器半径 const maxx = this.$refs.progress.offsetLeft + this.$refs.progress.offsetWidth - this.$refs.indicator.offsetWidth / 2 // 最小偏移=轴左偏移-指示器半径 const minx = this.$refs.progress.offsetLeft - this.$refs.indicator.offsetWidth / 2 // 只有手指在合理范围内才更新进度条和指示器 if (left <= maxx && left >= minx) { // 计算移动时的实际时间 var currentTime = moveTime + this.video.currentTime // 根据时间计算进度条宽度和指示器偏移 this.video.offsetCurrentTime = currentTime this.video.progress = (currentTime * 100) / this.video.duration this.$refs.progressCurrentLine.style.width = `${this.video.progress}%` var transformx = (currentTime * this.$refs.progress.offsetWidth) / this.video.duration - this.$refs.indicator.offsetWidth / 2 this.$refs.indicator.style.transform = `translateY(-50%) translateX(${transformx}px)` } }, TouchEnd(e) { // 取消拖动状态 this.video.isSlider = false // 直接seek时间即可 this.video.target.currentTime = +this.video.offsetCurrentTime.toFixed(2) // 兼容一些浏览器seek后不播放的问题(正常浏览器seek后自动播放) this.video.target.play() this.ShowControls() },

到这里我们的方法基本都实现了,我们可以运行一下看看手机上的各个端都有什么问题。这里推荐一下本人自研的局域网移动调试方法——移动开发快速预览调试的实现,本方法已成功申请专利。

总结

写代码和读书一样都容易产生心流,这也是我们热爱coding的一大主要原因,但是写是写出来了,效果会怎样呢?似乎没有第一次运行就满意的程序,我们这个demo在运行的过程中也会遇到很多的问题,下一篇我们会写一下实际运行的问题和改正的方法——项目调试

源文:如何快速开发一个自定义的视频播放器(3)——方法实现

如有侵权请联系站点删除!

Technical cooperation service hotline, welcome to inquire!