您的位置:首页 > 其它

模拟video播放器

2016-04-15 19:33 288 查看
更新:

关于第二点,也就是说计算进度条拖放按钮定位的问题。

很感谢 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: