模拟video播放器
2016-04-15 19:33
288 查看
更新:
关于第二点,也就是说计算进度条拖放按钮定位的问题。
很感谢 batsing 同学提供了更好的方案: 滑块左偏量 = (进度条长 - 滑块长) * (已播时间/总时长)
尝试过之后发现除了拖曳滑片的时候会抛锚外,其它暂时没发现什么问题,并且较之前的算法省了很多不必要的步骤,所以如今除了拖曳操作的时候使用旧方法外,已经进行修改。如果还有其它建议欢迎告诉我~~(づ ̄ 3 ̄)づ
正文:
本以为写一个video播放器不难,可写着写着坑就越挖越大了。
先看一下播放器大概是长这样的:
View Code
关于第二点,也就是说计算进度条拖放按钮定位的问题。
很感谢 batsing 同学提供了更好的方案: 滑块左偏量 = (进度条长 - 滑块长) * (已播时间/总时长)
尝试过之后发现除了拖曳滑片的时候会抛锚外,其它暂时没发现什么问题,并且较之前的算法省了很多不必要的步骤,所以如今除了拖曳操作的时候使用旧方法外,已经进行修改。如果还有其它建议欢迎告诉我~~(づ ̄ 3 ̄)づ
正文:
本以为写一个video播放器不难,可写着写着坑就越挖越大了。
先看一下播放器大概是长这样的:
'use strict'; //检测设备类型 var startWhen, endWhen, moveWhen; var u = navigator.userAgent; if ( u.match(/\b(Windows\sNT|Macintosh)\b/) ) { // 鼠标 startWhen = 'mousedown'; endWhen = 'mouseup'; moveWhen = 'mousemove'; } else { // 触摸屏 startWhen = 'touchstart'; endWhen = 'touchend'; moveWhen = 'touchmove'; } // 原生的JavaScript事件绑定函数 function bindEvent(ele, eventName, func){ if(window.addEventListener){ ele.addEventListener(eventName, func); } else{ ele.attachEvent('on' + eventName, func); } } function VideoContainer(options) { var t = this; t.volumeTol = options.volumeTol; t.video = options.video; t.pauseBtn = options.pause; t.progressBar = options.progressBar; t.timer = options.timer; t.volume = options.volume; t.volumeBar = options.volumeBar; t.volumeBarIcon = options.volumeBarIcon; t.progressBarIcon = options.progressBarIcon; t.fullScreenBtn = options.fullscreen; t.activeTol = ''; //载入视频 //获取视频总时长 t.video.addEventListener("canplaythrough", function(){ t.videoDuration = t.video.duration; t.tolTime = t.videoTime(t.videoDuration); t.timer.innerHTML = '00:00/' + t.tolTime.minutes_str + ':' + t.tolTime.seconds_str; }); //播放时间点更新 t.video.addEventListener("timeupdate", function(){ t.timeupdate = t.videoTime(t.video.currentTime); //更新时间 t.timer.innerHTML = t.timeupdate.minutes_str + ':' + t.timeupdate.seconds_str + '/' + t.tolTime.minutes_str + ':' + t.tolTime.seconds_str; t.activeTol = (t.progressBar.offsetWidth - t.progressBarIcon.offsetWidth) * ( t.video.currentTime / t.videoDuration ); t.progressBarIcon.style.left = t.activeTol + 'px'; t.progressBar.children[0].style.width = t.activeTol + 'px'; }); //设置默认音量 t.volumeTol = t.volumeTol ? t.volumeTol : 0.5; t.video.volume = t.volumeTol; t.volumeBar.children[0].style.width = t.volumeTol * 100 + '%'; t.volumeBarIcon.style.left = t.volumeTol * 100 + '%'; //各绑定事件 //暂停 t.pauseBtn.onclick = function() { t.videoPaused(); } //音量 t.volume.onclick = function() { t.videoMuted(); } //全屏 t.fullScreenBtn.onclick = function() { t.videoFullscreen(this); } t.liveEvent.call(t.progressBar, { _this: this, attribute: 'progressBar', moveing: false}); t.liveEvent.call(t.volumeBar, { _this: this, attribute: 'volumeBar', moveing: false}); t.liveEvent.call(t.progressBarIcon, { _this: this, attribute: 'progress_bar_icon', moveing: true}); t.liveEvent.call(t.volumeBarIcon, { _this: this, attribute: 'volume_bar_icon', moveing: true}); bindEvent(document, endWhen, function(e) { t._draging = false; }); } VideoContainer.prototype.liveEvent = function(options) { var t = options._this; //区分当前操作元素是拖动按钮还是它的父级 var _this = options.moveing ? this.parentNode : this; var _parentWidth = _this.offsetWidth; //检测设备类型 var _ua = function(e) { var Pos = null; if ( u.match(/\b(Windows\sNT|Macintosh)\b/) ) { e = e || window.event; Pos = { left : e.pageX, top: e.pageY } } else { var touch = e.targetTouches[0] || e.changedTouches[0] Pos = { left : touch.pageX , top: touch.pageY } } return Pos; }; //区分拖动的是进度条还是音量条 function playStep() { if (options.attribute == 'progress_bar_icon' || options.attribute == 'progressBar') { if(options.moveing === true) { //根据拖放的进度计算相对于占icon宽的多少 var init = t.progressBarIcon.offsetWidth / (_parentWidth / t._durCount.left); var progressBarIconWidth = t.progressBarIcon.offsetWidth; //拖放按钮是否超出范围 if ( t._durCount.left + progressBarIconWidth - init >= _parentWidth ){ t.video.currentTime = t.videoDuration; t.progressBar.children[0].style.width = _parentWidth + 'px'; t.progressBarIcon.style.left = _parentWidth - progressBarIconWidth + 'px'; } else{ t.video.currentTime = t.videoDuration / (_parentWidth / (t._durCount.left + init)); t.progressBar.children[0].style.width = t._durCount.left + 'px'; t.progressBarIcon.style.left = t._durCount.left + 'px'; } } else{ t.activeTol = (t.progressBar.offsetWidth - progressBarIconWidth) * ( t._durCount.left / _parentWidth ); t.progressBar.children[0].style.width = t._durCount.left + 'px'; t.video.currentTime = t.videoDuration / (_parentWidth / t._durCount.left); t.progressBarIcon.style.left = t.activeTol + 'px'; } } else{ if ( t._durCount.left + t.volumeBarIcon.offsetWidth >= _parentWidth ){ t.volumeTol = 1; } else if( t._durCount.left <= 0 ){ t.volumeTol = 0; } else { t.volumeTol = 1 / (_parentWidth / t._durCount.left); } //拖放按钮是否超出范围 if (t.volumeTol == 1) { t.volumeBarIcon.style.left = _parentWidth - t.volumeBarIcon.offsetWidth + 'px'; } else{ t.volumeBarIcon.style.left = t.volumeTol * 100 + '%'; } t.video.volume = t.volumeTol; t.volumeBar.children[0].style.width = t.volumeTol * 100 + '%'; } } //仅限拖动按钮可移动 if ( options.moveing === true) { bindEvent(this, moveWhen, function(e) { if (t._draging) { //鼠标移动了多少距离 t._mousePos = { left: (_ua(e).left - _this.offsetLeft) - t._startPos.left, top: (_ua(e).top - _this.offsetTop) - t._startPos.top } t._motion = true; //鼠标是否在拖动范围内 if (0 <= t._mousePos.left <= _parentWidth || 0 < t._mousePos.top <= _this.offsetHeight){ //移动后的坐标 = 上次记录的定位 + 鼠标移动了的距离; t._durCount = { left: t._oldPos.left + t._mousePos.left, top: t._oldPos.top + t._mousePos.top, }; playStep(); } else { t._draging = false; } } }); } bindEvent(this, startWhen, function(e) { // 防止选择文字、拖动页面(触摸屏)鼠标移动过快松开抛锚 e.preventDefault(); if ( this.setCapture ) { this.setCapture(); } //如果当前对象是拖动按钮,阻止冒泡 if (options.moveing === true) { e.stopPropagation(); } t._draging = true; t._motion = false; //记录按下鼠标到背景图片的距离 t._startPos = { left: _ua(e).left - _this.offsetLeft, top: _ua(e).top - _this.offsetTop } //当前拖动按钮的定位 t._oldPos = { left: this.offsetLeft, top: this.offsetTop }; //本次拖动的距离 t._durCount = t._startPos; }); bindEvent(this, endWhen, function(e) { t._draging = false; //如果进行的是拖动操作,则不必再更新视频的进度 if( !t._motion) { playStep(); } // 防止选择文字、拖动页面(触摸屏)鼠标移动过快松开抛锚 if (this.releaseCapture) { this.releaseCapture(); } delete t._draging; //是否拖动 delete t._startPos; //鼠标按下坐标 delete t._oldPos; //拖动按钮的定位 delete t._mousePos; //鼠标移动的距离 }); } //转换时间单位 VideoContainer.prototype.videoTime = function(time) { var timeId = {} var seconds = time > 0 ? parseInt(time) : 0; var minutes = parseInt(time / 60); seconds = seconds - minutes * 60; timeId.minutes_str = minutes < 10 ? '0' + minutes : minutes; timeId.seconds_str = seconds < 10 ? '0' + seconds : seconds; return timeId; } //是否全屏 VideoContainer.prototype.videoFullscreen = function() { var t = this; var element = t.video; //反射調用 var invokeFieldOrMethod = function(element, method) { var usablePrefixMethod; ["webkit", "moz", "ms", "o", ""].forEach(function(prefix) { if (usablePrefixMethod) return; if (prefix === "") { // 无前缀,方法首字母小写 method = method.slice(0,1).toLowerCase() + method.slice(1); } var typePrefixMethod = typeof element[prefix + method]; if (typePrefixMethod + "" !== "undefined") { if (typePrefixMethod === "function") { usablePrefixMethod = element[prefix + method](); } else { usablePrefixMethod = element[prefix + method]; } } }); return usablePrefixMethod; }; if( invokeFieldOrMethod(document,'FullScreen') || invokeFieldOrMethod(document,'IsFullScreen') || document.IsFullScreen ){ //退出全屏 if ( document.exitFullscreen ) { document.exitFullscreen(); } else if ( document.msExitFullscreen ) { document.msExitFullscreen(); } else if ( document.mozCancelFullScreen ) { document.mozCancelFullScreen(); } else if( document.oRequestFullscreen ){ document.oCancelFullScreen(); } else if ( document.webkitExitFullscreen ){ document.webkitExitFullscreen(); } else{ var docHtml = document.documentElement; var docBody = document.body; var videobox = element.parentNode; docHtml.style.cssText = ""; docBody.style.cssText = ""; videobox.style.cssText = ""; document.IsFullScreen = false; } } else { //進入全屏 //此方法不可以在異步任務中執行,否則火狐無法全屏 if(element.requestFullscreen) { element.requestFullscreen(); } else if(element.mozRequestFullScreen) { element.mozRequestFullScreen(); } else if(element.msRequestFullscreen){ element.msRequestFullscreen(); } else if(element.oRequestFullscreen){ element.oRequestFullscreen(); } else if(element.webkitRequestFullscreen){ element.webkitRequestFullScreen(); }else{ var docHtml = document.documentElement; var docBody = document.body; var videobox = element.parentNode; var cssText = 'width:100%;height:100%;overflow:hidden;'; docHtml.style.cssText = cssText; docBody.style.cssText = cssText; videobox.style.cssText = cssText+';'+'margin:0px;padding:0px;'; document.IsFullScreen = true; } } } //是否暂停 VideoContainer.prototype.videoPaused = function() { var t = this; if(t.video.paused) { t.video.play(); } else{ t.video.pause(); } } //调整音量 VideoContainer.prototype.videoMuted = function() { var t = this; if ( !t.video.defaultMuted ){ t.video.volume = 0; t.video.defaultMuted = true; t.volumeBar.children[0].style.width = 0 + '%'; t.volumeBarIcon.style.left = 0 + '%'; } else { t.video.volume = t.volumeTol; t.video.defaultMuted = false; t.volumeBar.children[0].style.width = t.volumeTol * 100 + '%'; //拖放按钮是否超出范围 if (t.volumeTol == 1) { t.volumeBarIcon.style.left = t.volumeBar.offsetWidth - t.volumeBarIcon.offsetWidth + 'px'; } else{ t.volumeBarIcon.style.left = t.volumeTol * 100 + '%'; } } }
View Code
相关文章推荐
- UIScrollView
- hdu 1114(完全背包)
- UVA 10651 Pebble Solitaire
- WinHttp方法通过HTTP协议向服务器发送请求,返回结果
- RxAndroid + Retrofit + Databinding
- [置顶] Who am I
- 剑指offer之面试题7:用两个栈实现队列
- 用C#创建XML文档和读取并修改XML文档
- bzoj 2251(后缀数组)
- 如何更方便快捷的调用restful服务
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- Hadoop初识--Hadoop单机模式安装和环境配置
- PAT1003.我要通过!(20)(简单的c语言风格c++解法)
- iOS个人整理39-cocoaPods的使用