一步一步实战HTML音乐播放器

来源:互联网 发布:大数据工程师面试题 编辑:程序博客网 时间:2024/05/22 02:01

在这里我用HTML5从头开始一步一步来制作一个简约的音乐播放器,大家可以参考一下,接下来正式开始。


音乐播放器效果


播放器分析

这里将播放器分两块来做:

  • 视图层(html + css)
  • 逻辑层 ( js )

视图层分析

视图中包含:

  • 播放器容器
    • 播放器名称
    • 音乐专辑图
    • 音乐信息
      • 歌曲名
      • 歌手
      • 专辑名
    • 控制区
      • 上一曲
      • 播放
      • 下一曲
    • 播放进度条
    • 播放时间
      • 当前时间
      • 歌曲总时间
    • 音频控件
  • 页面背景

逻辑层分析

逻辑层处理包括:

  • 加载歌单
  • 渲染歌曲信息
    • 专辑图
    • 歌曲名
    • 歌手
    • 专辑名
    • 歌曲时长
    • 歌曲音频地址
  • 监听控制按钮
    • 播放按钮 (修改播放状态)
    • 上一曲(判断歌单边界,重新渲染歌曲信息)
    • 下一曲(判断歌单边界,重新渲染歌曲信息)
  • 定时器
    • 同步歌曲当前时间和播放进度条
    • 歌曲播放完,自动切换下一曲

好了,播放器基本分析完成,接下来开始编码了,先进行视图层的编写。


视图层结构编写

根据我在上面的视图层分析,来构建HTML结构。

建立index.html,结构编码如下:

<!-- 页面背景 --><body>    <!-- 播放器容器 -->    <div class="player">        <!-- 播放器名称 -->        <div class="header">音乐播放器</div>        <!-- 音乐专辑图 -->        <div class="albumPic"></div>        <!-- 音乐信息  -->        <div class="trackInfo">            <!-- 歌曲名 -->            <div class="name"></div>            <!-- 歌手 -->            <div class="artist"></div>            <!-- 专辑名 -->            <div class="album"></div>        </div>        <!-- 播放进度条 -->        <div class="progress"></div>        <!-- 控制区  -->        <div class="controls">            <!-- 播放 -->            <div class="play">                <i class="icon-play"></i>            </div>            <!-- 上一曲 -->            <div class="previous">                <i class="icon-previous"></i>            </div>            <!-- 下一曲 -->            <div class="next">                <i class="icon-next"></i>            </div>        </div>              <!-- 播放时间  -->        <div class="time">            <!-- 当前时间 -->            <div class="current"></div>            <!-- 歌曲总时间 -->            <div class="total"></div>        </div>        <!-- 音频控件 -->        <audio id="audio"><source src=""></audio>    </div></body>

好了,结构编写完毕,接下来编写视图层样式。


视图层样式编写

:这里我是用LESS写的CSS,后面我会贴出完整代码,或者到 CSDN CODE 下载源码

先重置标记样式:

html, body, div, span, applet, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,a, abbr, acronym, address, big, cite, code,del, dfn, em, img, ins, kbd, q, s, samp,small, strike, strong, sub, sup, tt, var,b, u, i, center,dl, dt, dd, ol, ul, li,fieldset, form, label, legend,table, caption, tbody, tfoot, thead, tr, th, td,article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary,time, mark, audio, video {    margin: 0;    padding: 0;    border: 0;    font-size: 100%;    font: inherit;    vertical-align: baseline;}/* HTML5 display-role reset for older browsers */article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {    display: block;}body {    line-height: 1;}ol, ul {    list-style: none;}blockquote, q {    quotes: none;}blockquote:before, blockquote:after,q:before, q:after {    content: '';    content: none;}table {    border-collapse: collapse;    border-spacing: 0;}

设置body

//这里主要设置背景和flex布局,用于播放器垂直居中@body-bg: #111;html,body{    height: 100%;}body{    background-color: @body-bg;    display: flex;    align-items: center;    justify-content: center;    color: #fff;    font: 16px "微软雅黑";}

设置播放器容器 .player

//主要设置播放器的大小、背景颜色、定位等信息@player-bg: lighten(@body-bg, 10%);@player-w: 375px;@player-h: 550px;.player{    width: @player-w;    height: @player-h;    background-color: @player-bg;    border-radius: 10px;    position: relative;}

设置播放器名称.header样式:

.player{        .header{        padding: 15px 0;        text-align: center;    }}

专辑图.albumPic样式:

.player{    .albumPic{        background-image: url(http://p3.music.126.net/SR9eFEjRB0NsscxN7-fHMw==/3344714372906000.jpg); //这里先放一张临时图片,用于看效果,编写完成后,把这条属性删除即可        background-size: cover; //背景模式        width: @player-w * 0.72; //通过计算设置宽高,可直接用百分比        height: @player-w * 0.72;        margin: auto; //居中        border-radius: 10px;    }}

专辑信息区域样式:

.player{    .trackInfo{        text-align: center;        padding: 20px 0 15px;        font-size: 14px;        white-space: nowrap;        //单独将歌曲名设置一下大小        .name{            font-size: 24px;            margin-bottom: 10px;            font-weight: bold;        }    }}

播放进度条样式:

.player{    .progress{        width: 30%; //这里用于看效果,制作完成后,设置为0        height: 20%;        position: absolute; //用绝对定位放到播放器容器最下面和最左面        bottom: 0;        left: 0;        background-image: linear-gradient(top, rgba(255, 255, 255, 0), #0099FF); //背景采用从上到下的线性渐变        border-bottom-left-radius: 10px;        border-bottom-right-radius: 10px;        opacity: .4;    }}

按钮控制区域样式设置:

.player{    .controls{        //位置方面不用再额外设置了,按照对上面的设置,当前控制区的位置正好        position: relative;        //播放按钮同样采用flex布局,用于对内部的网络字体按钮垂直居中        .play{            cursor: pointer;            width: 75px;            height: 75px;            border: 2px solid #ccc;            border-radius: 50%; //加个圆框            margin: auto;            display: flex;            align-items:center;            justify-content:center;            color: #fff;            font-size: 35px;            &:hover{                font-size: 40px; //鼠标经过变大字体            }        }        //上、下一曲 共用样式        .btn(){            cursor: pointer;            position: absolute;                     top: 25px;            font-size: 30px;            &:hover{                font-size: 32px;            }        }        //设置一下按钮位置        .previous{              .btn;                   left: 60px;        }        .next{            .btn;            right: 60px;        }    }}

播放时间区域设置:

.player{    .time{        width: @player-w - 40px; //计算pdding后的宽度,可自行计算        display: flex;        position: absolute;        bottom: 0;        padding: 20px;        align-items: center;        justify-content: space-between; //两端分布    }}

好了,通过上面的样式设置,播放器的视图层已完毕,看下效果(三个播放控制按钮是引用的字体):

接下来开始编写逻辑层。


逻辑层编写

逻辑层用到了Jquery和歌曲清单数据playlist.js,先引用一下:

<script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/playlist.js"></script>

playlist.js就是一堆json的歌单数据,数据是从网易云音乐上获取的,基本内容如下:

//因为做静态页有跨域问题,所以就直接把数据拿出来赋值给`playlist`这个对象上了,下面只保留了需要用到的数据对象var playlist = {    "result": {        "tracks": [            {                "name": "歌曲名",                "artists": [                    {                        "name": "演唱者",                    }                ],                "album": {                    "name": "专辑名",                    "picUrl":专辑图",                "duration": 时长(ms),                "mp3Url": "音乐地址"            },            ...//等等等        ],    },};

网易云音乐歌单json数据接口:http://music.163.com/api/playlist/detail?id=xxx

建立index.js,开始编码:

先定义一个播放状态对象playStatus

//当前播放器状态var playStatus = {    currentTrackLen: playlist.result.tracks.length, //歌单歌曲数    currentTrackIndex: 0, //当前播放的歌曲索引,默认加载第一首歌    currentTime: 0, //当前歌曲播放的时间    currentTotalTime: 0, //当前歌曲的总时间    playStatus: true, //true为播放状态,false为暂停状态};

因为要用到时间的转换,所以编写一个时间转换函数:

var timeConvert = function(timestamp){    var minutes = Math.floor(timestamp / 60);    var seconds = Math.floor(timestamp - (minutes * 60));    if(seconds < 10) {      seconds = '0' + seconds;    }    timestamp = minutes + ':' + seconds;    return timestamp;};

接下来编写一个对象,内部方法是控制播放器的:

//播放器控制方法对象var playerControls = {    //歌曲基本信息设置    trackInfo: function(args){        //playerlist是playlist.js中的歌单数据,根据需求进行数据读取即可        var obj = playlist.result.tracks[playStatus.currentTrackIndex];        args = args || {            name:obj.name,            artist:obj.artists[0].name,            album:obj.album.name,            albumPic:obj.album.picUrl + '?param=270y270',            total:obj.duration,            src: obj.mp3Url,        };        $('.player .trackInfo .name').text(args.name);        $('.player .trackInfo .artist').text(args.artist);        $('.player .trackInfo .album').text(args.album);           $('.player .albumPic').css('background','url(' + args.albumPic + ')');                 $('.player .time .total').text(timeConvert(args.total / 1000)); //因为歌单数据中的播放长度用ms表示的,所以这里 / 1000        playStatus.currentTotalTime = Math.floor(args.total / 1000);        $('#audio source').attr('src',args.src); //切换音乐通过修改<source>中的src    },    //播放、暂停状态处理    playStatus: function(){        $('.player .controls .play i').attr('class', 'icon-' + (playStatus.playStatus?'pause':'play'));        if(playStatus.playStatus){            //用jquery获取<audio>对象,必须加上[0]            $('#audio')[0].play();        }else{            $('#audio')[0].pause();        }    },    //当前时间和进度处理    playTime: function(){        $('.player .time .current').text(timeConvert(playStatus.currentTime));        $('.player .progress').css('width', playStatus.currentTime / playStatus.currentTotalTime * 100 + '%'); //同步进度条    }};

还剩下一个初始化方法了:

var init = function(){    //置一下歌曲信息和播放状态    playerControls.trackInfo();         playerControls.playStatus();    //播放按钮事件监听    $('.player .controls .play').click(function(){        //修改播放状态        playStatus.playStatus = !playStatus.playStatus;         //置播放信息        playerControls.playStatus();    });    //上一曲按钮事件监听    $('.player .controls .previous').click(function(){        //边界判断        if(playStatus.currentTrackIndex - 1 < 0){            alert('已经没有上一首了');        }else{            playStatus.currentTrackIndex --;        }        //此处切换歌曲功能,原来打算采用直接修改src的方法实现,但是修改src后,之前播放的音乐还继续播放着,切换后的音乐却不播放,所以最终采用移除<audio>,再加入<audio>的方式来切换音乐        $('#audio').remove();        $('.player').append('<audio id="audio"><source src=""></audio>');          //更新音轨信息和播放状态               playerControls.trackInfo();        playerControls.playStatus();    });    //下一曲按钮事件监听    $('.player .controls .next').click(function(){        if(playStatus.currentTrackIndex + 1 >= playStatus.currentTrackLen){            alert('已经没有下一首了');        }else{            playStatus.currentTrackIndex ++;        }        //换src的方法没法切换声音,试了好几种方法都不行,只能删了再重建了        $('#audio').remove();        $('.player').append('<audio id="audio"><source src=""></audio>');                  playerControls.trackInfo();        playerControls.playStatus();    });    //用时钟来实时修改当前播放时间及播放完当前曲目自动下一曲    setInterval(function(){        playStatus.currentTime = $('#audio')[0].currentTime;                   playerControls.playTime();        if(playStatus.currentTime >= playStatus.currentTotalTime){            $('.player .controls .next').click();        }    }, 300);};

其后,再加入init()执行一下就OK了。


完整代码

index.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>H5音乐播放器</title>    <link rel="stylesheet" type="text/css" href="css/index.css">    <script type="text/javascript" src="js/jquery.min.js"></script>    <script type="text/javascript" src="js/playlist.js"></script>    <script type="text/javascript" src="js/index.js"></script></head><body>    <div class="player">        <div class="header">音乐播放器</div>        <div class="albumPic"></div>        <div class="trackInfo">            <div class="name"></div>            <div class="artist"></div>            <div class="album"></div>        </div>        <div class="progress"></div>        <div class="controls">            <div class="play">                <i class="icon-play"></i>            </div>            <div class="previous">                <i class="icon-previous"></i>            </div>            <div class="next">                <i class="icon-next"></i>            </div>        </div>              <div class="time">            <div class="current"></div>            <div class="total"></div>        </div>        <audio id="audio"><source src=""></audio>    </div></body></html>

index.css

@import 'reset.css';@import 'fonts.css';html,body {  height: 100%;}body {  background-color: #111111;  display: -webkit-box;  display: -webkit-flex;  display: -ms-flexbox;  display: flex;  -webkit-box-align: center;  -webkit-align-items: center;      -ms-flex-align: center;          align-items: center;  -webkit-box-pack: center;  -webkit-justify-content: center;      -ms-flex-pack: center;          justify-content: center;  color: #fff;  font: 16px "微软雅黑";}.player {  width: 375px;  height: 550px;  background-color: #2b2b2b;  border-radius: 10px;  position: relative;}.player .header {  padding: 15px 0;  text-align: center;}.player .albumPic {  background-size: cover;  width: 270px;  height: 270px;  margin: auto;  border-radius: 10px;}.player .trackInfo {  text-align: center;  padding: 20px 0 15px;  font-size: 14px;  white-space: nowrap;}.player .trackInfo .name {  font-size: 24px;  margin-bottom: 10px;  font-weight: bold;}.player .progress {  width: 0;  height: 20%;  position: absolute;  bottom: 0;  left: 0;  background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0), #0099ff);  background-image: linear-gradient(top, rgba(255, 255, 255, 0), #0099ff);  border-bottom-left-radius: 10px;  border-bottom-right-radius: 10px;  opacity: .4;}.player .controls {  position: relative;}.player .controls .play {  cursor: pointer;  width: 75px;  height: 75px;  border: 2px solid #ccc;  border-radius: 50%;  margin: auto;  display: -webkit-box;  display: -webkit-flex;  display: -ms-flexbox;  display: flex;  -webkit-box-align: center;  -webkit-align-items: center;      -ms-flex-align: center;          align-items: center;  -webkit-box-pack: center;  -webkit-justify-content: center;      -ms-flex-pack: center;          justify-content: center;  color: #fff;  font-size: 35px;}.player .controls .play:hover {  font-size: 40px;}.player .controls .previous {  cursor: pointer;  position: absolute;  top: 25px;  font-size: 30px;  left: 60px;}.player .controls .previous:hover {  font-size: 32px;}.player .controls .next {  cursor: pointer;  position: absolute;  top: 25px;  font-size: 30px;  right: 60px;}.player .controls .next:hover {  font-size: 32px;}.player .time {  width: 335px;  display: -webkit-box;  display: -webkit-flex;  display: -ms-flexbox;  display: flex;  position: absolute;  bottom: 0;  padding: 20px;  -webkit-box-align: center;  -webkit-align-items: center;      -ms-flex-align: center;          align-items: center;  -webkit-box-pack: justify;  -webkit-justify-content: space-between;      -ms-flex-pack: justify;          justify-content: space-between;}

index.js

$().ready(function(){    //当前播放器状态    var playStatus = {        currentTrackLen: playlist.result.tracks.length,        currentTrackIndex: 0,        currentTime: 0,        currentTotalTime: 0,        playStatus: true,    };    //播放器控制方法    var playerControls = {        //歌曲基本信息        trackInfo: function(args){            var obj = playlist.result.tracks[playStatus.currentTrackIndex];            args = args || {                name:obj.name,                artist:obj.artists[0].name,                album:obj.album.name,                albumPic:obj.album.picUrl + '?param=270y270',                total:obj.duration,                src: obj.mp3Url,            };            $('.player .trackInfo .name').text(args.name);            $('.player .trackInfo .artist').text(args.artist);            $('.player .trackInfo .album').text(args.album);               $('.player .albumPic').css('background','url(' + args.albumPic + ')');                     $('.player .time .total').text(timeConvert(args.total / 1000));            playStatus.currentTotalTime = Math.floor(args.total / 1000);            $('#audio source').attr('src',args.src);        },        //播放、暂停状态处理        playStatus: function(){            $('.player .controls .play i').attr('class', 'icon-' + (playStatus.playStatus?'pause':'play'));            if(playStatus.playStatus){                $('#audio')[0].play();            }else{                $('#audio')[0].pause();            }        },        //当前时间和进度处理        playTime: function(){            $('.player .time .current').text(timeConvert(playStatus.currentTime));            $('.player .progress').css('width', playStatus.currentTime / playStatus.currentTotalTime * 100 + '%');        }    };    var timeConvert = function(timestamp){        var minutes = Math.floor(timestamp / 60);        var seconds = Math.floor(timestamp - (minutes * 60));        if(seconds < 10) {          seconds = '0' + seconds;        }        timestamp = minutes + ':' + seconds;        return timestamp;    };    (function(){        playerControls.trackInfo();             playerControls.playStatus();        $('.player .controls .play').click(function(){            playStatus.playStatus = !playStatus.playStatus;             playerControls.playStatus();        });        $('.player .controls .previous').click(function(){            if(playStatus.currentTrackIndex - 1 < 0){                alert('已经没有上一首了');            }else{                playStatus.currentTrackIndex --;            }            $('#audio').remove();            $('.player').append('<audio id="audio"><source src=""></audio>');                      playerControls.trackInfo();            playerControls.playStatus();        });        $('.player .controls .next').click(function(){            if(playStatus.currentTrackIndex + 1 >= playStatus.currentTrackLen){                alert('已经没有下一首了');            }else{                playStatus.currentTrackIndex ++;            }            //换src的方法没法切换声音,试了好几种方法都不行,只能删了再重建了            $('#audio').remove();            $('.player').append('<audio id="audio"><source src=""></audio>');                      playerControls.trackInfo();            playerControls.playStatus();        });        setInterval(function(){            playStatus.currentTime = $('#audio')[0].currentTime;                       playerControls.playTime();            if(playStatus.currentTime >= playStatus.currentTotalTime){                $('.player .controls .next').click();            }        }, 300);    })();});

代码下载

下载完整源码


博客名称:王乐平博客

博客地址:http://blog.lepingde.com

CSDN博客地址:http://blog.csdn.net/lecepin

3 0