在这里我用HTML5从头开始一步一步来制作一个简约的音乐播放器,大家可以参考一下,接下来正式开始。
这里将播放器分两块来做:
视图中包含:
逻辑层处理包括:
好了,播放器基本分析完成,接下来开始编码了,先进行视图层的编写。
根据我在上面的视图层分析,来构建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); //切换音乐通过修改
},
//播放、暂停状态处理
playStatus: function(){
$('.player .controls .play i').attr('class', 'icon-' + (playStatus.playStatus?'pause':'play'));
if(playStatus.playStatus){
//用jquery获取
$('#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').remove();
$('.player').append(' ');
//更新音轨信息和播放状态
playerControls.trackInfo();
playerControls.playStatus();
});
//下一曲按钮事件监听
$('.player .controls .next').click(function(){
if(playStatus.currentTrackIndex + 1 >= playStatus.currentTrackLen){
alert('已经没有下一首了');
}else{
playStatus.currentTrackIndex ++;
}
//换src的方法没法切换声音,试了好几种方法都不行,只能删了再重建了
$('#audio').remove();
$('.player').append(' ');
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
:
<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(' ');
playerControls.trackInfo();
playerControls.playStatus();
});
$('.player .controls .next').click(function(){
if(playStatus.currentTrackIndex + 1 >= playStatus.currentTrackLen){
alert('已经没有下一首了');
}else{
playStatus.currentTrackIndex ++;
}
//换src的方法没法切换声音,试了好几种方法都不行,只能删了再重建了
$('#audio').remove();
$('.player').append(' ');
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