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 里没有做音量控制和这个音量渐进、减退,因为感觉 没多大用....尤其是在手机端都有这个音控的按键前提下....)

 

上图:

HTML5 播放器

 

上代码:

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('&nbsp;').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)