HTML5 播放器
之前一个前端群里 大牛 做了一个自适应的HMLT5播放器
最近根据其思路做了一个相对单一移动端的demo,demo用的图片和歌曲json的数据设计 都是群里大牛做的,在这谢谢~;
同时借鉴的几篇文章:
慕课网 : http://www.imooc.com/view/299 (这个我也没看完....)
leinov : http://www.cnblogs.com/leinov/p/3896772.html (完整的音频的解释demo)
陈在真 :http://blog.sina.com.cn/s/blog_74d6cedd0102vkbr.html (也是这篇文章 让我在这次demo 里没有做音量控制和这个音量渐进、减退,因为感觉 没多大用....尤其是在手机端都有这个音控的按键前提下....)
上图:
上代码:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML5 播放器</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description" content="">
<meta name="apple-touch-fullscreen" content="yes" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
<meta content="no" name="apple-mobile-web-app-capable" />
<meta content="black" name="apple-mobile-web-app-status-bar-style" />
<meta content="telephone=no" name="format-detection" />
<style>
*{margin:0;padding:0;}
li{ list-style: none;}
a{ text-decoration: none;}
html,body{width:100%; height:100%; font-family: 'microsoft yahei', Arial, Helvetica, sans-serif;}
body{-webkit-tap-highlight-color: rgba(0,0,0,0); }
.tac{ text-align:center;}
.fl{ float:left;}
.fr{ float:right;} .body_bg{transition:opacity 0.5s ease-in; position:absolute;left:0;top:0; width:100%; height:100%; background-image:url(bg.jpg) 0 0 no-repeat; background-size: cover; opacity: 0;}
.body_bg.cur{opacity:1;}
.list_main{overflow-y: auto;}
.list_ul{ width:100%;}
.list_ul li{ position:relative; min-height: 55px; font-size: 14px; padding:0 20px; color:#fff; line-height: 20px;}
.list_ul li.cur{ color:#f48e4a;}
.list_line{ position:absolute;left:0;bottom:0; width:100%; height:1px; background: rgba(0,0,0,.3);}
.list_ul .music_mian{ position:absolute;top:50%;transform: translateY(-50%);}
.list_ul p{ font-size: 14px;}
.audio_main{ position:fixed; bottom:0;left:0; width:100%; height:100px;background:rgba(0,0,0,.3); }
.process_line{ position:relative; width:100%; height:3px; background-color: #fff; }
.progress_after{ position:absolute;left:0;top:0; width:0px; height:3px; background-color: #f48e4a;}
.process_main{ }
.music_time{ color:#fff; font-size: 12px;margin:5px;}
.music_btn{ position:absolute;bottom:0;left:50%; width:238px; transform: translateX(-50%);}
.music_btn a{ display:inline-block; width:60px; height:46px; background:url(player.png) no-repeat 0 0; font-size: 0;}
.music_btn .music_before{background-position:-143px 0; }
.music_btn .music_switch{ background-position:-68px 0;margin-right:20px;}
.music_btn .cur{ background-position:-68px -140px;}
.music_btn .music_after{background-position:0px 0;margin-right:20px;} .name_singer{ color:#fff; margin:5px; font-size:12px;}
.audio_dot{ position:absolute;left:0;top:-6px; width:14px; height:14px;border-radius: 50%; background:#fff;}
.audio_Bgdot{ position:absolute;left:-15px;top:-15px; width:44px; height:44px;background:rgba(0,0,0,0);}
.turn{ position:absolute;left: -36px;bottom: 12px; width:30px;height:30px; text-align:center;line-height: 30px; font-size: 14px; color:#fff;}
</style>
<script type="text/javascript" src="zepto.js"></script>
<script type="text/javascript" src="music.js"></script> <script type="text/javascript">
$(function(){ var audios = [
{
name:'知己',
singer:'未知',
src:'02.mp3',
cover:''
},
{
name:'暗号',
singer:'周杰伦',
src:'01.mp3',
cover:'cover.jpg'
},
{
name:'One Day.mp3',
singer:'Kodaline',
src:'03.mp3',
cover:''
},
{
name:'KOK',
singer:'未知',
src:'KOK.mp3',
cover:''
},
{
name:'一块红布',
singer:'',
src:'04.mp3',
cover:''
},
{
name:'Hall Of Fame ',
singer:'The Script Feat Will.I.Am',
src:'05.mp3',
cover:''
},
{
name:'Rumour Has It',
singer:'未知',
src:'06.mp3',
cover:''
},
{
name:'寻找',
singer:'李志',
src:'08.mp3',
cover:''
},
{
name:'Rooftops',
singer:'Kris Allen',
src:'07.mp3',
cover:''
}
]; Music.init(audios); }); </script>
</head> <body style="background-image:url(bg.jpg); opacity:1; ">
<div class="body_bg" style="background-image:url(bg.jpg); opacity:1; "></div>
<div class="list_main" id="list_main">
<ul class="list_ul" id="list_ul"> </ul>
</div>
<div class="audio_main" id="audio_main">
<div class="process_main">
<div class="process_line" id="process_line">
<div class="progress_after" id="line_after"></div>
<div class="audio_dot" id="dot">
<div class="audio_Bgdot"></div>
</div>
</div>
</div>
<div class="fl music_time" id="time_start">00:00</div>
<div class="fr music_time" id="time_end">00:00</div>
<div class="tac name_singer" id="name_txt"></div>
<div class="tac name_singer" id="singer_txt"></div>
<div class="music_btn">
<a href="javascript:;" class="music_after" id="music_after"></a>
<a href="javascript:;" class="music_switch" id="music_switch"></a>
<a href="javascript:;" class="music_before" id="music_before"></a>
<div class="turn" id="turn">顺</div>
</div>
</div>
</body>
</html>
js:
var Music = {
init : function( data ){
this.data = [];//存储数据;
this.randomArr = [];
for( var i=0,len=data.length;i<len;i++ ) {
if( data[i].src ){
this.data.push( data[i] );
this.randomArr.push(i);
}
} this._getElement(); //获取dom;
this.createAudio()//创建音频;
this.createMusicList(); //创建歌单; },
_getElement : function(){
this.list_ul = $('#list_ul');
this.music_switch = $('#music_switch');
this.music_before = $('#music_before');
this.music_after = $('#music_after');
this.time_start = $('#time_start');
this.time_end = $('#time_end');
this.process_line = $('#process_line');
this.line_after = $('#line_after');
this.window = $(window);
this.bodybg = $('.body_bg');
this.dot = $('#dot');
this.turn = $('#turn');
this.trunNum = 0;
this._dot = document.getElementById('dot');
this._process_line = document.getElementById('process_line');
this.Time = null;
this.startPic = this.bodybg.css('backgroundImage');
this.dragBtn = false;
this.playing = false;
},
_bindElement : function(){
var that = this;
var that = this; this.turn.click(function(){
that.trunNum++; var status = that.trunNum % 3;
switch(status){
case 0:
that.turn.html('顺');
break;
case 1:
that.randomArr.sort(function(){
return Math.random()>0.5?-1:1;
});
that.turn.html('随');
break;
case 2:
that.turn.html('单');
break;
}
}); //下一首歌
this.music_before.click(function(){
that._beforeMusic();
}); //上一首歌
this.music_after.click(function(){
that._afterMusic()
}); this.music_switch.on('click',function(){
that._fnPlay();
}); this.lineW = this.process_line.width() - this.dot.width();
function _touchstart( event ){ that.dragBtn = true; that.maxX = that.process_line.width() - that.dot.width(); event.stopPropagation();
} function _touchmove( event ){
var touch = event.targetTouches[0];
var moverX = touch.pageX;
that.dragBtn = true;
moverX = moverX < 0 ? 0 : moverX;
moverX = moverX > that.maxX ? that.maxX : moverX; that.dot.css('left',moverX);
that.line_after.css('width',moverX);
that.dragX = touch.pageX;
event.stopPropagation();
} function _touchend( event ){
var touch = event.targetTouches[0];
event.stopPropagation();
_tapLine();
}
this.process_line.click(function(event){
var eX = event.clientX > that.lineW ? that.lineW : event.clientX; that.dot.css('left',eX);
that.line_after.css('width',eX);
_tapLine();
});
function _tapLine(){
var l = parseFloat(that.dot.css('left'));
var maxL = parseFloat(that.lineW);
that._audio.currentTime = that._percentage( l,maxL,that._audio.duration);
clearInterval(that.Time);
that._musicTimer();
that.dragBtn = false;
} this._dot.addEventListener('touchstart',_touchstart,false);
this._dot.addEventListener('touchmove',_touchmove,false);
this._dot.addEventListener('touchend',_touchend,false);
},
createAudio : function(){
var html = '<audio id="audio" >您的浏览器不支持音频元素。</audio>';
$('body').append(html);
this._audio = document.getElementById('audio');
},
createMusicList : function(){
var that = this;
var html = '';
var data = this.data;
this._getHeight();
for( var i=0,len=data.length;i<len;i++ ){
var name,singer,src,pic; if( toStrings(data[i].name).length > 0){
name = toStrings(data[i].name);
}else{
name = '未知';
}
if( toStrings(data[i].singer).length > 0){
singer = toStrings(data[i].singer);
}else{
singer = '未知';
} /*
if( data[i].cover ){
pic = data[i].cover;
}else{
pic = this.startPic;
}
*/
pic = data[i].cover;
src = data[i].src; html += '<li music_index='+i+' music_name='+ name +' music_singer='+ singer +' music_src='+src+' music_pic='+ pic +'>'
+'<div class="music_mian">'
+ '<p class="music_name">'+name+'</p>'
+ '<p class="music_singer">'+singer+'</p>'
+ '</div>'
+ '<div class="list_line"></div>'
+'</li>'; }
this.list_ul.html(html); //列表绑定事件;
this.list_ul.on('click','li',function(){ that._bindElement();//创建事件;
that._cutSongs(this); }); //转换字符去掉空格;
function toStrings( txt ){
return txt.split(' ').join(' ').toString();
}
},
_afterMusic : function(){
var status = this.trunNum % 3;
var current = this.list_ul.find('.cur');
var index = current.index();
var maxLen = this.data.length-1;
var obj; if( status == 0 || status == 2 ){
if( index == 0 ){ obj = this.list_ul.find('li').last(); }else if( index > 0 ){ obj = current.prev(); }
}else if( status == 1 ){
for(var i=0;i<maxLen;i++){
if( this.randomArr[i] == index ){
var num = i;
num--;
if( num <= 0 ){
num = maxLen;
}
obj = this.list_ul.find('li').eq(this.randomArr[num]);
}
}
}
this._cutSongs(obj);
},
_beforeMusic : function(){
var status = this.trunNum % 3;
var current = this.list_ul.find('.cur');
var index = current.index();
var maxLen = this.data.length-1;
var obj; if( status == 0 || status == 2 ){
if( index == maxLen ){ obj = this.list_ul.find('li').first(); }else if( index < maxLen ){ obj = current.next(); }
}else if( status == 1 ){
for(var i=0;i<maxLen;i++){
if( this.randomArr[i] == index ){
var num = i;
num++;
if( num >= maxLen ){
num = 0
}
obj = this.list_ul.find('li').eq(this.randomArr[num]);
}
}
}
this._cutSongs(obj);
},
_cutSongs : function( obj ){
this.playing = true;
$(obj).addClass('cur').siblings('li').removeClass('cur');
var music_src = $(obj).attr('music_src');
var music_pic = $(obj).attr('music_pic');
var music_name = $(obj).attr('music_name');
var music_singer = $(obj).attr('music_singer'); $('#name_txt').html(music_name);
$('#singer_txt').html(music_singer); if( music_pic ){
this.bodybg.attr('style','background-image:url('+music_pic+');' );
}else{
this.bodybg.css('backgroundImage',this.startPic+';');
}
this.bodybg.addClass('cur'); this._audio.src = music_src; this._fnPlay();
},
_getHeight :function(){
var wH = $(window).height();
var mH = $('#audio_main').height();
var $musicMain = $('#list_main');
var h = wH - mH;
$musicMain.height(h); },
_fnPlay : function(){
var that = this; if( this._audio.paused ){ //判断是否重新加载歌曲
if(this.playing){
this._audio.load(); this.playing = false;
} this._audio.play();
this.music_switch.addClass('cur');
this._audio.addEventListener('loadeddata',function(){
var timerMain = that._toTime(that._audio.duration);
var len = timerMain.split(':').length; switch(len){
case 1:
that.time_start.html('00');
break;
case 2:
that.time_start.html('00:00');
break;
} that.time_end.html(timerMain);
that._musicTimer(); },false); }else{
this._audio.pause();
this.music_switch.removeClass('cur');
clearInterval(that.Time);
} },
_percentage:function( a,b,c ){
return a/b*c;
},
_musicTimer : function(){
var that = this;
this.Time = setInterval(_snowTime,1000);
var timerMain = that._toTime(that._audio.duration);
var len = timerMain.split(':').length;
function _snowTime(){ if( that._audio.currentTime == that._audio.duration ){
clearInterval(that.Time);
var status = that.trunNum % 3;
switch(status){
case 0:
that._beforeMusic();
break;
case 1:
that._beforeMusic();
break;
case 2:
var current = that.list_ul.find('.cur');
that._cutSongs(current);
break;
} } if(!that.dragBtn){
var timerMain = that._toTime(that._audio.currentTime);
var l = that._percentage( that._audio.currentTime,that._audio.duration,parseFloat(that.lineW) );
that.dot.css('left',l);
that.line_after.css('width',l);
} switch( len ){
case 1:
that.time_start.html(timerMain);
break;
case 2:
var timer = timerMain.indexOf(':')>0?timerMain:'00:'+timerMain;
that.time_start.html(timer);
break; } }
},
_toTime : function( time ){
var hour = Math.floor(time/3600);
var min = Math.floor(time%3600/60);
var sec = Math.floor(time%60); var ih = hour <= 9 ? '0'+hour : hour;
var im = min <= 9 ? '0'+min :min;
var is = sec <= 9 ? '0'+sec :sec;
return ( ih > 0 ? ih+':' : '') + (im >0 ? im+':' :'') +is;
}
}
总结:
最开始想用 面向对象的方式写,但是后来还是觉得json单体的写法更实用
个人简单粗暴的判断方法是:
页面 单一功能的应用 就用 json单体;
页面 某功能多次调用 就用 面向对象 比如: tab选项卡、轮播之类的;
hml5 audio 的新的api 文上的连接讲比较详尽就不赘述了
遇到的个人一些小问题:
一:第一次用这个 zepto.js 感觉跟 jQuery 一样,不过这个 tap 的事件怎么绑定不上 后来还是用 click 代替了 之前听说在 click 在移动端有延迟 也因为是用了 zepto 库还没绑定上完全用的跟 JQuery 似的也让我很尴尬,同时也因为用了库在 dom 的获取也用了原生所以在这个dom存储上有所难以区分(当然我知道这对象可以转成原生,最后还是用了纯原生的方式获取),因为 audio 有很多新的属性 都需要原生;
二:单体的this 指向 需要不停的 存成 that在用 有点繁琐;
三:歌曲时间想做到小时以上 比如 : 01:02:05 这样 后来 在这个当前播放时间设置 _snowTime() 里 判断一句就是 _toTime()返回 当前播放秒数转成分钟形式的字符串 (如:00:00:00)里的":"的个数,在时间补零(00:00:05)上 还要在用这个 ':'做判断觉得恶心,后来看了酷狗的播放器上过小时的也是用分钟的形式展示(120:30)目前还没想到什么好一点解决方法,也可以说是目前的一个已知 bug 吧;
四:最初的功能方法上想的比较独立单一,起初以为 “上一首歌”,“下一首歌”,和“歌曲播放到最后的下一首歌” 都是 独立的 其“歌曲播放到最后的下一首歌”其实之分两种一种是单曲循环,第二种是“下一首歌” 所以 “歌曲播放到最后的下一首歌” 区分不是 “单曲循环” 模式 剩下都是 “下一首歌” 里的功能 在“下一首歌”里做这个 歌曲模式“随机”、“顺序”播放的下一首就可是了;
五:在做这个“歌曲进度”拖动的时候,和这个歌曲正常播放 设置 “歌曲进度” 的冲突,后来建立that.dragBtn 判断是拖动还是仅仅是歌曲进度的设置,同样的问题还有这个 当前歌曲的暂停之后的播放和切割之后的播放 是有所不同的,歌曲的切换时是换了audio的路径 需要audio.load() 从新加载才能播放同样创建了this.playing 来判断是否切歌;
六:歌曲模式的设置 最开始想多了 想建立一个 json {‘顺’,‘随’,‘单’} 做对应关系,后来发现 其实只需要一个 num 做累加取余去判断即可;
功能总结:顺序播放、随机播放、单曲循环、上下换歌、点击切歌、拖动歌曲的进度;
没做功能:没有音控、手机转屏从新设置....没怎么做适配,仅仅适配自己的手机,肯定还有Bug和代码如何在优化欢迎指出;
谢谢 大牛们 写的技术文章做过的demo的共享~
HTML5 播放器的更多相关文章
- 7款超具个性的HTML5播放器
这篇文章我们要分享一些很有个性的HTML5音乐播放器和视频播放器,它们都具有播放器的大部分功能,并以HTML5和JavaScript实现.这些HTML5播放器有着非常漂亮的外观,很多你都无需自己重新定 ...
- HTML5播放器 MediaElement.js 使用方法
目前已经有很多html5播放器可以使用,使用html5播放器可以轻松的在页面中插入媒体视频,从而使我们的web页面变得更加丰富多彩,所以今 天向大家推荐一款非常优秀的html5播放器MediaElem ...
- HTML5播放器实例
鉴于html5Audio and video的使用,设计了一个自定义风格的播放器,除实现一些基本的默认功能之外,还实现了一些高级功能. 具体功能如下: 实现播放暂停按钮 实现静音按钮 实现音量调节滑动 ...
- .NET MVC对接POLYV——HTML5播放器播放加密视频
官方参考文档:http://dev.polyv.net/2017/videoproduct/v-playerapi/html5player/html5-docs/ 1.上传视频之前根据自己需要对所上传 ...
- HTML5播放器FlowPlayer的极简风格效果
在线演示 本地下载 使用Flowplayer生成的极简风格的播放器效果.
- HTML5——播放器
有了H5的Video,妈妈再也不用担心我没安Flash插件了 根据Video提供的方法和属性,简单练习了一下,不说废话,直接上图片和代码 <html><head><tit ...
- CKPlayer 只调用HTML5播放器时全屏问题 这只是Chrome浏览器的渲染bug
如题,在系统中使用CKPlayer播放器,一切顺利,偶然发现没有全屏按钮, 正常的全屏按钮是这样的: 经过一步步调试,发现问题出在iframe, 当视频页面在iframe内时,全屏按钮不显示了,这个和 ...
- wap html5播放器和直播开发小结
此文已由作者吴家联授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 去年年中的时候,借着产品改版的机会,将之前的h5播放器好好整理重构了一番.之前的h5播放器较为简陋,有几个大 ...
- html5播放器制作小结
链接:http://snowinmay.net/6rooms/html/music.php 9月份前的版本: 播放,暂停,点赞,播放状态显示. 9.2版本: 下载歌曲,静音,时间倒计时(点击暂停时倒计 ...
随机推荐
- 在Java中如何高效的判断数组中是否包含某个元素
原文出处: hollischuang(@Hollis_Chuang) 如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Ove ...
- HDU 6375(双端队列 ~)
题意是有至多150000个双端队列,400000次简单操作,直接开会导致内存超限,所以用 STL 中的 map 和 deque ,而读入过大已经在题目中有所说明,直接用已经给出的快速读入即可.要注意的 ...
- Shell编程(八)每隔N分钟执行某脚本
sudo crontab -e
- css的几个小技巧
本文收录css设置样式的一些小技巧 1. 设置文字在块级标签居中(包括水平居中和垂直居中) 水平居中 方法一:使用text-align text-align:center 方法二:目标标签的父级标签设 ...
- DataTabe使用Linq实现 Group
DataTable dt = dataSet.Tables[]; var query = from t in dt.AsEnumerable() group t by new { t1 = t.Fie ...
- PHP中遍历二维数组—以不同形式的输出操作
<body> <?php //定义二维索引数组$arr = array( array("101","李军","男", ...
- ubuntu安装matplotlib一些坑
ubuntu16.04,python2.7 安装matplotlib, 1.在root权限下执行命令 pip install matplotlib==1.5.1 这里有个困扰我一个星期的问题,系统都被 ...
- 数据库设计理论与实践·<二>概念设计与逻辑设计
2一.概念设计 1.1 概念设计关键知识 1.2 辨析 实体与属性的区别: ①实体能进一步用多个属性来描述,属性却不能,属性是不可再细分/分割的原子项. ②实体内部或者多个实体之间存在联系,而属性无. ...
- 可见参数和增强for以及自动拆装箱
可变参数:定义方法的时候不知道该定义多少个参数格式: 修饰符 返回值类型 方法名(数据类型… 变量名){ } 注意: 这里的变量其实是一个数组如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定 ...
- 【数据表格】datatable+SpringMVC+Spring Data JPA
初步实现 $("#userTable").dataTable({ "processing": true, "serverSide": tru ...