zoukankan      html  css  js  c++  java
  • 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('&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的共享~

  • 相关阅读:
    (全国多校重现赛一) H Numbers
    (全国多校重现赛一)E-FFF at Valentine
    (全国多校重现赛一)B-Ch's gifts
    (全国多校重现赛一)A-Big Binary Tree
    UVA-10391 Compoud Words
    HDU-1027Ignatius and princess II
    CodeForces-501B
    UVA-136Ugly numbers
    UVA-101
    UVA-10474
  • 原文地址:https://www.cnblogs.com/auok/p/4420407.html
Copyright © 2011-2022 走看看