HTML代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>html音樂播放器</title>
<link rel="stylesheet" href="font/iconfont.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="player">
<!-- 歌曲信息模塊 -->
<div id="player-content1">
<!-- 歌曲名 -->
<div class="music-name"></div>
<!-- 歌手名 -->
<div class="artist-name"></div>
<!-- 歌曲時間 -->
<div class="time">
<!-- 當前播放的時間 -->
<div class="current-time"></div>
<!-- 歌曲總時長 -->
<div class="total-time"></div>
</div>
<!-- 進度條 -->
<div id="s-area">
<!-- 鼠標移動到進度條上,顯示的時間信息 -->
<div id="ins-time"></div>
<!-- 鼠標移動到進度條上,進度條變暗部分-->
<div id="s-hover"></div>
<!-- 表示當前歌曲播放進度的藍色進度條 -->
<div id="seek-bar"></div>
</div>
</div>
<!-- 控制模塊 -->
<div id="player-content2">
<!-- 左側歌曲封面旋轉模塊 -->
<div class="music-imgs">
<!-- 封面圖 -->
<div class="img"></div>
<!-- 歌曲緩衝時的提示文字 -->
<div id="buffer-box">緩衝…</div>
</div>
<!-- 右側歌曲操作模塊 -->
<div class="player-controls">
<!-- 上一首按鈕 -->
<div class="btn prev iconfont"></div>
<!-- 暫停/播放 按鈕 -->
<div class="btn play-pause icon-jiediankaishi iconfont"></div>
<!-- 下一首按鈕 -->
<div class="btn next iconfont"></div>
</div>
</div>
</div>
<script src="js/jquery-3.4.1.min.js"></script>
<script src="js/index.js"></script>
</body>
</html>
CSS部分講解:
裏面有幾處用到了CSS3動畫:
動畫一:點擊 播放/暫停
按鈕, 歌曲信息模塊向上/向下
移動
/* 歌曲信息模塊 */
#player-content1{
position: absolute;
top:0px;
left:15px;
width:320px;
height:90px;
padding:0 20px 0 130px;
background: rgb(209, 226, 245);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* transition過渡動畫:設置top屬性過渡,過渡時間0.3s,速度曲線爲ease(逐漸變慢) */
transition:top 0.3s ease;
}
#player-content1.active{
top:-85px;
}
通過JS部分的代碼,動態給歌曲信息模塊(id爲player-content1
)的DOM元素添加/移除active類名
。
設置CSS3動畫過渡屬性: transition:top 0.3s ease;
來生成過渡時間0.3s,速度逐漸變慢的:
上移動畫效果:top:0px;
——>top:-85px;
下移動畫效果: top:-85px;
——>top:0px;
同理,左側圖片的旋轉,移動,陰影等動畫效果:
1. 封面圖上移/下移
出現陰影/陰影消失
的動畫效果:
/* 左側封面圖模塊 */
.music-imgs{
position: absolute;
top: -40px;
width: 100px;
height: 100px;
margin-left: 30px;
-webkit-transform: rotateZ(0);
transform: rotateZ(0);
transition: 0.3s ease all;
box-shadow: 0 0 0 10px #fff;
border-radius: 50%;
overflow: hidden;
}
/* 左側封面圖模塊添加了active類名 */
.music-imgs.active{
top: -50px;
box-shadow: 0 0 0 4px #e8f5ff, 0 30px 50px -15px #afb7c1;
}
通過JS控制給封面圖模塊(類名爲music-imgs
)添加/移除active
類名
結合transition: 0.3s ease all;
來生成:圓形封面圖上移並且下方出現陰影的效果
2. 封面圖旋轉的動畫效果
/* 左側封面圖模塊下的 圖片div */
.music-imgs .img{
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('../img/bg.jpg');
}
/* 封面圖模塊添加了active類名後,圖片div的樣式添加 */
.music-imgs.active .img{
z-index: 1;
-webkit-animation: rotateAlbumArt 3s linear 0s infinite forwards;
animation: rotateAlbumArt 3s linear 0s infinite forwards;
}
@-webkit-keyframes rotateAlbumArt
{
0%{ -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
@keyframes rotateAlbumArt
{
0%{ -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
這裏用到了css3的animation
屬性
animation
屬性:比較類似於 flash 中的逐幀動畫;- 在 CSS3 中是由屬性
keyframes
來完成逐幀動畫的;
animation: rotateAlbumArt 3s linear 0s infinite forwards;
rotateAlbumArt
: 綁定的keyframe
名稱
3s
:動畫變化時間爲3s
linear
: 動畫從頭到尾的速度是相同的
0s
: 動畫開始之前的延遲時間,這裏爲0s,即不延遲
infinite
: 設置動畫無限循環播放
forwards
: 表示動畫結束後,元素直接使用當前樣式。
@keyframes rotateAlbumArt
{
0%{ -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
設置開始幀(0%):沿着Z軸旋轉度數爲0
設置結束幀(100%):沿着Z軸旋轉度數爲360
推薦:前端實現動畫的方法總結
全部CSS代碼如下:
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
#player{
position: relative;
top: 100px;
left:200px;
}
/* 歌曲信息模塊 */
#player-content1{
position: absolute;
top:0px;
left:15px;
width:320px;
height:90px;
padding:0 20px 0 130px;
background: rgb(209, 226, 245);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* transition過渡動畫:設置top屬性過渡,過渡時間0.3s,速度曲線爲ease(逐漸變慢) */
transition:top 0.3s ease;
}
#player-content1.active{
top:-85px;
}
.music-name,
.artist-name{
height: 20px;
margin-top:5px;
font-size:14px;
}
.artist-name{
font-size:12px;
color: #656565
}
.time{
font-size:12px;
height:15px;
margin: 5px 0;
}
.current-time{
float: left;
}
.total-time{
float: right;
}
.current-time,.total-time{
color: transparent;
font-size: 11px;
background-color: #e8f5ff;
border-radius: 10px;
transition: 0.3s ease all;
}
.time.active .current-time, .time.active .total-time{
color: rgb(54, 127, 196);
background-color: transparent;
}
#s-area, #seek-bar{
position: relative;
height: 4px;
border-radius: 4px;
}
#s-area{
background-color:#e8f5ff;
cursor: pointer;
}
#ins-time{
position: absolute;
top: -29px;
color: #fff;
font-size: 12px;
white-space: pre;
padding: 5px 6px;
border-radius: 4px;
display:none;
}
#s-hover{
position: absolute;
top: 0;
bottom: 0;
left: 0;
opacity: 0.2;
z-index: 2;
}
#ins-time, #s-hover{
background-color: #4b4d5c;
}
#seek-bar{
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 0;
background-color: rgb(54, 127, 196);
transition: 0.2s ease width;
}
#player-content2{
position: relative;
width:350px;
height:90px;
background: #fff;
border-radius: 20px;
box-shadow: 0 30px 80px #656565;
}
/* 左側封面圖模塊 */
.music-imgs{
position: absolute;
top: -40px;
width: 100px;
height: 100px;
margin-left: 30px;
-webkit-transform: rotateZ(0);
transform: rotateZ(0);
transition: 0.3s ease all;
box-shadow: 0 0 0 10px #fff;
border-radius: 50%;
overflow: hidden;
}
/* 左側封面圖模塊添加了active類名 */
.music-imgs.active{
top: -50px;
box-shadow: 0 0 0 4px #e8f5ff, 0 30px 50px -15px #afb7c1;
}
.music-imgs:before{
content: '';
position: absolute;
top: 50%;
right: 0;
left: 0;
width: 20px;
height: 20px;
margin: -10px auto 0 auto;
background-color: #d6dee7;
border-radius: 50%;
box-shadow: inset 0 0 0 2px #fff;
z-index: 2;
}
/* 左側封面圖模塊下的 圖片div */
.music-imgs .img{
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* 封面圖模塊添加了active類名後,圖片div的樣式添加 */
.music-imgs.active .img{
z-index: 1;
-webkit-animation: rotateAlbumArt 3s linear 0s infinite forwards;
animation: rotateAlbumArt 3s linear 0s infinite forwards;
}
@-webkit-keyframes rotateAlbumArt
{
0%{ -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
@keyframes rotateAlbumArt
{
0%{ -webkit-transform: rotateZ(0); transform: rotateZ(0); }
100%{ -webkit-transform: rotateZ(360deg); transform: rotateZ(360deg); }
}
#buffer-box
{
position: absolute;
top: 50%;
right: 0;
left: 0;
height: 13px;
color: #1f1f1f;
font-size: 13px;
font-family: Helvetica;
text-align: center;
font-weight: bold;
line-height: 1;
padding: 6px;
margin: -12px auto 0 auto;
background-color: rgba(255, 255, 255, 0.19);
opacity: 0;
z-index: 2;
}
.music-imgs .img, #buffer-box
{
transition: 0.1s linear all;
}
.music-imgs.buffering .img
{
opacity: 0.25;
}
.music-imgs.buffering .img.active
{
opacity: 0.8;
filter: blur(2px);
-webkit-filter: blur(2px);
}
.music-imgs.buffering #buffer-box
{
opacity: 1;
}
.player-controls{
position: absolute;
top:20px;
left:150px;
}
.player-controls .btn{
float: left;
width:60px;
height:60px;
line-height: 60px;
font-size:24px;
color:#D6DEE7;
}
JS部分講解
緩衝效果:
當我把歌曲鏈接改成錯誤的時候:
緩衝部分JS:
// 定時器檢測是否需要緩衝
function checkBuffering(){
clearInterval(buffInterval);
buffInterval = setInterval(function()
{
// 這裏如果音頻播放了,則nTime爲當前時間毫秒數,如果沒播放則爲0;如果時間間隔過長,也將緩存
if( (nTime == 0) || (bTime - nTime) > 1000 ){
musicImgs.addClass('buffering'); // 添加緩存樣式類
} else{
musicImgs.removeClass('buffering'); // 移除緩存樣式類
}
bTime = new Date();
bTime = bTime.getTime();
},100);
}
全部JS代碼(內含詳細註釋):
$(function(){
var playerContent1 = $('#player-content1');// 歌曲信息模塊部分dom元素
var musicName = $('.music-name'); // 歌曲名部分dom元素
var artistName = $('.artist-name'); // 歌手名部分dom元素
var musicImgs = $('.music-imgs'); // 左側封面圖dom元素
var playPauseBtn = $('.play-pause'); // 播放/暫停按鈕 dom元素
var playPrevBtn = $('.prev'); // 上一首按鈕 dom元素
var playNextBtn = $('.next') // 下一首按鈕 dom元素
var time = $('.time'); // 時間信息部分 dom元素
var tProgress = $('.current-time'); // 當前播放時間文本部分 dom元素
var totalTime = $('.total-time'); // 歌曲總時長文本部分 dom元素
var sArea = $('#s-area'); // 進度條部分
var insTime = $('#ins-time'); // 鼠標移動至進度條上面,顯示的信息部分
var sHover = $('#s-hover'); // 鼠標移動至進度條上面,前面變暗的進度條部分
var seekBar = $('#seek-bar'); // 播放進度條部分
// 一些計算所需的變量
var seekT, seekLoc, seekBarPos, cM, ctMinutes, ctSeconds, curMinutes, curSeconds, durMinutes, durSeconds, playProgress, bTime, nTime = 0
var musicImgsData = ['img/bg.jpg','img/bg1.jpg','img/bg2.jpg'] // 圖片地址數組
var musicNameData = ['出山','盜將行','歸去來兮']; // 歌曲名數組
var artistNameData = ['花粥/王勝娚','花粥/馬雨陽','花粥'] // 創作歌手數組
var musicUrls=['mp23/music1.mp3','mp3/music2.mp3','mp3/music3.mp3'];// 歌曲mp3數組
var currIndex = -1; // 當前播放索引
var buffInterval = null // 初始化定時器 判斷是否需要緩衝
var len = musicNameData.length; // 歌曲長度
// 點擊 播放/暫停 按鈕,觸發該函數
// 作用:根據audio的paused屬性 來檢測當前音頻是否已暫停 true:暫停 false:播放中
function playPause(){
if(audio.paused){
playerContent1.addClass('active'); // 內容欄上移
musicImgs.addClass('active'); // 左側圖片開始動畫效果
playPauseBtn.attr('class','btn play-pause icon-zanting iconfont') // 顯示暫停圖標
checkBuffering(); // 檢測是否需要緩衝
audio.play(); // 播放
}else{
playerContent1.removeClass('active'); // 內容欄下移
musicImgs.removeClass('active'); // 左側圖片停止旋轉等動畫效果
playPauseBtn.attr('class','btn play-pause icon-jiediankaishi iconfont'); // 顯示播放按鈕
clearInterval(buffInterval); // 清除檢測是否需要緩衝的定時器
musicImgs.removeClass('buffering'); // 移除緩衝類名
audio.pause(); // 暫停
}
}
// 鼠標移動在進度條上, 觸發該函數
function showHover(event){
seekBarPos = sArea.offset(); // 獲取進度條長度
seekT = event.clientX - seekBarPos.left; //獲取當前鼠標在進度條上的位置
seekLoc = audio.duration * (seekT / sArea.outerWidth()); //當前鼠標位置的音頻播放秒數: 音頻長度(單位:s)*(鼠標在進度條上的位置/進度條的寬度)
sHover.width(seekT); //設置鼠標移動到進度條上變暗的部分寬度
cM = seekLoc / 60; // 計算播放了多少分鐘: 音頻播放秒速/60
ctMinutes = Math.floor(cM); // 向下取整
ctSeconds = Math.floor(seekLoc - ctMinutes * 60); // 計算播放秒數
if( (ctMinutes < 0) || (ctSeconds < 0) )
return;
if( (ctMinutes < 0) || (ctSeconds < 0) )
return;
if(ctMinutes < 10)
ctMinutes = '0'+ctMinutes;
if(ctSeconds < 10)
ctSeconds = '0'+ctSeconds;
if( isNaN(ctMinutes) || isNaN(ctSeconds) )
insTime.text('--:--');
else
insTime.text(ctMinutes+':'+ctSeconds); // 設置鼠標移動到進度條上顯示的信息
insTime.css({'left':seekT,'margin-left':'-21px'}).fadeIn(0); // 淡入效果顯示
}
// 鼠標移出進度條,觸發該函數
function hideHover()
{
sHover.width(0); // 設置鼠標移動到進度條上變暗的部分寬度 重置爲0
insTime.text('00:00').css({'left':'0px','margin-left':'0px'}).fadeOut(0); // 淡出效果顯示
}
// 鼠標點擊進度條,觸發該函數
function playFromClickedPos()
{
audio.currentTime = seekLoc; // 設置音頻播放時間 爲當前鼠標點擊的位置時間
seekBar.width(seekT); // 設置進度條播放長度,爲當前鼠標點擊的長度
hideHover(); // 調用該函數,隱藏原來鼠標移動到上方觸發的進度條陰影
}
// 在音頻的播放位置發生改變是觸發該函數
function updateCurrTime()
{
nTime = new Date(); // 獲取當前時間
nTime = nTime.getTime(); // 將該時間轉化爲毫秒數
// 計算當前音頻播放的時間
curMinutes = Math.floor(audio.currentTime / 60);
curSeconds = Math.floor(audio.currentTime - curMinutes * 60);
// 計算當前音頻總時間
durMinutes = Math.floor(audio.duration / 60);
durSeconds = Math.floor(audio.duration - durMinutes * 60);
// 計算播放進度百分比
playProgress = (audio.currentTime / audio.duration) * 100;
// 如果時間爲個位數,設置其格式
if(curMinutes < 10)
curMinutes = '0'+curMinutes;
if(curSeconds < 10)
curSeconds = '0'+curSeconds;
if(durMinutes < 10)
durMinutes = '0'+durMinutes;
if(durSeconds < 10)
durSeconds = '0'+durSeconds;
if( isNaN(curMinutes) || isNaN(curSeconds) )
tProgress.text('00:00');
else
tProgress.text(curMinutes+':'+curSeconds);
if( isNaN(durMinutes) || isNaN(durSeconds) )
totalTime.text('00:00');
else
totalTime.text(durMinutes+':'+durSeconds);
if( isNaN(curMinutes) || isNaN(curSeconds) || isNaN(durMinutes) || isNaN(durSeconds) )
time.removeClass('active');
else
time.addClass('active');
// 設置播放進度條的長度
seekBar.width(playProgress+'%');
// 進度條爲100 即歌曲播放完時
if( playProgress == 100 )
{
playPauseBtn.attr('class','btn play-pause icon-jiediankaishi iconfont'); // 顯示播放按鈕
seekBar.width(0); // 播放進度條重置爲0
tProgress.text('00:00'); // 播放時間重置爲 00:00
musicImgs.removeClass('buffering').removeClass('active'); // 移除相關類名
clearInterval(buffInterval); // 清除定時器
}
}
// 定時器檢測是否需要緩衝
function checkBuffering(){
clearInterval(buffInterval);
buffInterval = setInterval(function()
{
// 這裏如果音頻播放了,則nTime爲當前時間毫秒數,如果沒播放則爲0;如果時間間隔過長,也將緩存
if( (nTime == 0) || (bTime - nTime) > 1000 ){
musicImgs.addClass('buffering'); // 添加緩存樣式類
} else{
musicImgs.removeClass('buffering'); // 移除緩存樣式類
}
bTime = new Date();
bTime = bTime.getTime();
},100);
}
// 點擊上一首/下一首時,觸發該函數。
//注意:後面代碼初始化時,會觸發一次selectTrack(0),因此下面一些地方需要判斷flag是否爲0
function selectTrack(flag)
{
// 初始 || 下一首
if( flag == 0 || flag == 1 )
++currIndex;
else
--currIndex;
if( (currIndex > -1) && (currIndex < len) ){
if( flag == 0 )
playPauseBtn.attr('class','btn play-pause icon-jiediankaishi iconfont'); // 顯示播放圖標
else
{
musicImgs.removeClass('buffering');
playPauseBtn.attr('class','btn play-pause icon-zanting iconfont') // 顯示暫停圖標
}
seekBar.width(0); // 重置播放進度條爲0
time.removeClass('active');
tProgress.text('00:00'); // 播放時間重置
totalTime.text('00:00'); // 總時間重置
// 獲取當前索引的:歌曲名,歌手名,圖片,歌曲鏈接等信息
currMusic = musicNameData[currIndex];
currArtist = artistNameData[currIndex];
currImg = musicImgsData[currIndex];
audio.src = musicUrls[currIndex];
nTime = 0;
bTime = new Date();
bTime = bTime.getTime();
// 如果點擊的是上一首/下一首 則設置開始播放,添加相關類名,重新開啓定時器
if(flag != 0){
audio.play();
playerContent1.addClass('active');
musicImgs.addClass('active');
clearInterval(buffInterval);
checkBuffering();
}
// 將歌手名,歌曲名,圖片鏈接,設置到元素上
artistName.text(currArtist);
musicName.text(currMusic);
musicImgs.find('.img').css({'background':'url('+currImg+')'})
}
else{
// 歌曲播放到最後一首/第一首 再點擊下一首/上一首 無效
if( flag == 0 || flag == 1 )
--currIndex;
else
++currIndex;
}
}
// 初始化函數
function initPlayer() {
audio = new Audio(); // 創建Audio對象
selectTrack(0); // 初始化第一首歌曲的相關信息
audio.loop = false; // 取消歌曲的循環播放功能
playPauseBtn.on('click',playPause); // 點擊播放/暫停 按鈕,觸發playPause函數
// 進度條 移入/移出/點擊 動作觸發相應函數
sArea.mousemove(function(event){ showHover(event); });
sArea.mouseout(hideHover);
sArea.on('click',playFromClickedPos);
// 實時更新播放時間
$(audio).on('timeupdate',updateCurrTime);
// 上下首切換
playPrevBtn.on('click',function(){ selectTrack(-1);} );
playNextBtn.on('click',function(){ selectTrack(1);});
}
// 調用初始化函數
initPlayer();
});
代碼太多了,我就不一個個拆開來了。註釋已經寫了很多了。
你們加油!
放上github源代碼地址:https://github.com/zoyoy1203/musicPlayer
試了下,百度網盤放不了 (¬_¬)ノ