前言:音乐播放器是前端开发中的一个经典项目,通过它可以掌握很多核心技术,如音频处理、DOM操作、事件监听、动画效果等。这个项目不仅能提升前端开发的技能,还能让开发者深入理解JavaScript与HTML的协同作用。
页面展示:
歌曲页面+列表(html代码):
音乐
下面有详细的注释讲解,大家可以对照着上图中的结构进行理解,当然也可以自己写,大家了解我的思路就行
<div class="wrapper">
<div class="player-warp">
<!-- 歌曲信息卡片(隐藏页面) -->
<div class="player-info">
<div class="info">
<div class="name">
<h4>我记得</h4>
</div>
<div class="singer-album">赵雷-署前街少年</div>
<div class="music-progress">
<!-- 时间显示 -->
<div class="music-progress-top">
<!-- 当前时间 -->
<span class="current-time">00:00</span>
<!-- 歌曲总时间 -->
<span class="time">05:29</span>
</div>
<!-- 音乐进度线 -->
<div class="music-progress-bar">
<!-- 绘制播放线 -->
<div class="music-progress-line"></div>
</div>
</div>
</div>
</div>
<!-- 歌曲控制页面 -->
<div class="player-control">
<div class="cover">
<img src="" alt="">
</div>
<!-- 控制按钮 -->
<div class="control">
<i id="prevBtn" class="iconfont"></i>
<i id="playBtn" class="iconfont paused"></i>
<i id="nextBtn" class="iconfont"></i>
<i id="openModal" class="iconfont"></i>
</div>
</div>
</div>
</div>
<!-- 设置音乐背景页面 -->
<div class="bg"></div>
<!-- 绘制歌曲列表 -->
<div class="modal">
<div class="modal-box">
<!-- 设置模块头部内容 -->
<div class="modal-box-top">
<div class="modal-title">
<h3>音乐列表</h3>
</div>
<div class="modal-close">
<!-- 放置让模块消失的图标 -->
<i class="iconfont"></i>
</div>
</div>
<div class="modal-wrapper">
<!-- 容器 -->
<ul class="song-list">
</ul>
</div>
</div>
</div>
<!-- 音乐-->
<audio src=""></audio>
<script src="./js/jquery.js"></script>
页面功能介绍:
1.点击播放按钮,音乐开始播放,歌曲信息将自然弹出,页面中的圆形图片开始旋转
2.点击前进和后退按钮,音乐和页面信息将进行相应改变
3.点击模块列表内容,可播放该音乐
js功能实现:
家人们我是通过jQuery实现的
1.使用ajax请求音乐数据
通过ajax请求数据,并且调用更新页面数据的函数,在页面中显示第一个歌曲, 添加音乐列表
let musicList = [];
let currentIndex = 0; // 当前播放音乐的下标
// Ajax 获取音乐数据
$.ajax({
type: "GET",
url: "./music.json",
success: function (data) {
musicList = data;
render(musicList[currentIndex]); // 渲染当前音乐
renderMusicList(musicList); // 渲染音乐列表
}
});
2.页面渲染信息函数:
获得jQuery包装级对象包装级对象,并且通过text()方法,在对象中添加数据
// 渲染音乐详情
function render(data) {
$(".name h4").text(data.name);
$(".time").text(data.time);
$(".singer-album").text(`${data.singer} - ${data.album}`);
$(".cover img").attr("src", data.cover);
$("audio").attr("src", data.audio_url);
$('.bg').css({
background: `url("${data.cover}") no-repeat center center`,
"background-size": "cover"
});
}
3.播放和暂停音乐:
设置点击播放按钮,将暂停按钮变成播放按钮,并且显示歌曲信息,大家可以通过上面视频了解
// 绑定播放按钮事件
$("#playBtn").on("click", togglePlay);
// 播放与暂停音乐
function togglePlay() {
//返回dom对象
let audio = $("audio").get(0);
if (audio.paused) {
$("#playBtn").removeClass("paused").addClass("running").html('');
$(".player-info").animate({ top: '-95%' }, 'slow');
$(".cover").css({ "animation-play-state": "running" });
audio.play();
} else {
$("#playBtn").removeClass("running").addClass("paused").html('');
$(".player-info").animate({ top: '0%' }, 'slow');
$(".cover").css({ "animation-play-state": "paused" });
audio.pause();
}
}
4.渲染音乐列表:
通过js动态添加歌曲列表
// 渲染音乐列表
function renderMusicList(list) {
$(".song-list").empty();
$.each(list, function (index, item) {
let isPlaying = (index == currentIndex && !$("audio").get(0).paused);
let $li = $(`
<li id="${index}" class="${index == currentIndex ? 'playing' : ''}">
<span>${index + 1}.${item.name} - ${item.singer}</span>
<span class="iconfont">${isPlaying ? '' : ''}</span>
</li>
`);
$(".song-list").append($li);
});
}
5.更新播放函数:
这个方法会被重复利用,所以封装起来 ,更新当前音乐信息,更新列表
// 更新并播放音乐
function updateAndPlay() {
render(musicList[currentIndex]);
$("#playBtn").trigger("click");
renderMusicList(musicList);
}
6.上下按钮点击事件:
点击前进和后退按钮更换歌曲事件,通过currentIndex变化更换当前歌词(因为当前歌词是通过currentIndex下标进行控制的)
// 绑定上一首、下一首按钮事件
$("#prevBtn").on("click", playPrev);
// 播放上一首音乐
function playPrev() {
currentIndex = (currentIndex > 0) ? currentIndex - 1 : musicList.length - 1;
updateAndPlay();
}
$("#nextBtn").on("click", playNext);
// 播放下一首音乐
function playNext() {
currentIndex = (currentIndex < musicList.length - 1) ? currentIndex + 1 : 0;
updateAndPlay();
}
7.更新音乐条的进度:
根据当前音乐的时间,获得值的百分比赋值给进度表的宽度
// 格式化时间
function formatTime(time) {
let min = Math.floor(time / 60);
let sec = Math.floor(time % 60);
return `${min < 10 ? '0' : ''}${min}:${sec < 10 ? '0' : ''}${sec}`;
}
// 更新播放时间和进度条
$("audio").on("timeupdate", function () {
let audio = $("audio").get(0);
let currentTime = audio.currentTime || 0;
let duration = audio.duration || 0;
$(".current-time").text(formatTime(currentTime));
$(".time").text(formatTime(duration));
let value = (currentTime / duration) * 100;
$(".music-progress-line").css({ width: value + "%" });
});
8.显示模块列表:
点击两个小图标点开音乐列表和关闭音乐列表
// 打开和关闭音乐列表弹窗
$("#openModal").on("click", function () {
$(".modal").css({ display: "block" });
renderMusicList(musicList); // 渲染音乐列表
});
$(".modal-close").on("click", function () {
$(".modal").css({ display: "none" });
});
9.点击音乐列表播放音乐事件:
点击列表相应歌曲播放点击歌曲
// 点击音乐列表播放对应歌曲
$(".song-list").on("click", "li", function () {
currentIndex = parseInt($(this).attr("id"));
updateAndPlay(); // 播放选择的音乐
});
10.音乐结束事件:
这个我设置的是 playNext () 播放下一个歌曲,大家还可以自己进行其他操作
// 监听音乐播放完毕的事件,自动播放下一首
$("audio").on("ended", function () {
playNext();
});
源代码:
上面HTML代码和JavaScript代码都是完整的,大家可以直接取上面的
CSS:
* {
margin: 0;
padding: 0;
}
body {
user-select: none;
background-color: #dadada;
}
/* 动画 */
@keyframes circle {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.wrapper {
width: 360px;
height: 80px;
margin: auto;
margin-top: 200px;
}
.player-warp {
position: relative;
}
.player-info {
width: 90%;
height: 100%;
position: absolute;
/* top: -95%; */
top: 0;
left: 5%;
z-index: -1;
background-color: rgba(255, 255, 255, 0.15);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
backdrop-filter: blur(3.5px);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.17);
display: flex;
justify-content: flex-end;
}
.player-info .info {
padding: 5px;
width: 60%;
font-size: 15px;
}
/* 进度条%比 */
.info .music-progress {
width: 100%;
}
.music-progress .music-progress-top {
display: flex;
color: #ff668c;
justify-content: space-between;
}
/* 绘制歌曲进程背景 */
.music-progress .music-progress-bar {
width: 100%;
height: 3px;
background-color: #b8b8b8;
border-radius: 10px;
margin-top: 3px;
}
/* 绘制覆盖线 */
.music-progress .music-progress-line {
width: 0%;
height: 90%;
background-color: #ff5a94;
}
.player-warp .player-control {
width: 360px;
height: 80px;
background-color: #ffffff;
border-radius: 15px;
display: flex;
z-index: 10;
}
.player-control .cover {
position: relative;
/* margin-left: 20px; */
left: 30px;
width: 104px;
height: 100px;
border-radius: 50px;
background-color: #ffffff;
margin-top: -60px;
animation: circle 5s infinite linear;
animation-play-state: paused;
}
.player-control img {
position: absolute;
top: 5%;
left: 5%;
width: 90%;
height: 90px;
border-radius: 50%;
}
.player-control .cover::before {
content: "";
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
}
.player-control .control {
margin-left: 20px;
width: 70%;
display: flex;
align-items: center;
justify-content: space-around;
}
.player-control .control i {
display: block;
color: #b05757;
font-size: 45px;
margin-right: 6px;
cursor: pointer;
transition: all 0.4s;
}
.control i:hover {
color: #e2a3a3 !important;
}
.bg {
position: absolute;
top: 0;
left: 0;
z-index: -2;
width: 100%;
height: 100%;
background: url("http://p2.music.126.net/34YW1QtKxJ_3YnX9ZzKhzw==/2946691234868155.jpg") no-repeat center center;
transform: scale(2);
/* 模糊 */
filter: blur(50px);
transition: all 1s;
}
li {
list-style: none;
}
.modal {
width: 100%;
height: 100%;
background-color: rgba(128, 128, 128, 0.25);
/* 设置固定定位 */
position: fixed;
top: 0;
right: 0;
display: none;
}
.modal .modal-box {
width: 30%;
height: 100%;
background-color: #fff;
position: absolute;
top: 0;
right: 0;
padding: 5px;
}
.modal-box .modal-close .iconfont {
font-size: 23px;
}
.modal-box .modal-box-top {
width: 100%;
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 5px;
}
.modal-box .modal-wrapper li {
cursor: pointer;
display: block;
height: 30px;
line-height: 30px;
display: flex;
justify-content: space-between;
margin-bottom: 4px;
background-color: rgba(230, 230, 230, 0.37);
border-bottom: 1px solid rgb(83, 83, 83);
}
.modal-box .modal-wrapper li span {
display: block;
font-size: 18px;
}
.modal-box .modal-wrapper li .iconfont {
font-size: 28px;
}
.modal-box .modal-wrapper li .iconfont:hover {
font-size: 30px;
}
.playing span {
color: #00ddc3;
}
music.json:
[
{
"name": "勇敢爱",
"audio_url": "./audios/Mi2 - 勇敢爱 [mqms2].mp3",
"singer": "Mi2",
"album": "吴少华",
"cover": "./img/7.png",
"time": "04:16"
},
{
"name": "一人饮酒醉(柔情版)",
"audio_url": "./audios/程嘉敏 - 一人饮酒醉 (柔情版) [mqms].mp3",
"singer": "程嘉敏",
"album": "吴少华",
"cover": "./img/1.png",
"time": "01:20"
},
{
"name": "明月天涯",
"audio_url": "./audios/等什么君 - 明月天涯 [mqms2].mp3",
"singer": "等什么君",
"album": "吴少华",
"cover": "./img/2.png",
"time": "04:14"
},
{
"name": "生僻字",
"audio_url": "./audios/陈柯宇 - 生僻字.mp3",
"singer": "陈柯宇",
"album": "吴少华",
"cover": "./img/3.png",
"time": "03:36"
},
{
"name": "依存症",
"audio_url": "./audios/东京塔子 - 依存症 [mqms2].mp3",
"singer": "东京塔子",
"album": "吴少华",
"cover": "./img/4.png",
"time": "04:39"
},
{
"name": "恶魔的爱",
"audio_url": "./audios/李宏毅&李明霖 - 恶魔的爱 [mqms2].mp3",
"singer": "李宏毅&李明霖",
"album": "吴少华",
"cover": "./img/5.png",
"time": "04:12"
},
{
"name": "梦回还",
"audio_url": "./audios/呦猫UNEKO - 梦回还 [mqms2].mp3",
"singer": "呦猫UNEKO",
"album": "吴少华",
"cover": "./img/6.png",
"time": "04:10"
},
{
"name": "当归",
"audio_url": "./audios/宿雨涵 - 当归.ogg",
"singer": "宿雨涵",
"album": "吴少华",
"cover": "./img/8.png",
"time": "03:54"
},
{
"name": "时光笔墨",
"audio_url": "./audios/张碧晨 - 时光笔墨.ogg",
"singer": "张碧晨",
"album": "吴少华",
"cover": "./img/9.png",
"time": "05:01"
},
{
"name": "勾指起誓",
"audio_url": "./audios/泠鸢yousa - 勾指起誓.ogg",
"singer": "泠鸢yousa",
"album": "吴少华",
"cover": "./img/10.png",
"time": "03:03"
},
{
"name": "散仙如烟",
"audio_url": "./audios/醋醋 - 散仙如烟.ogg",
"singer": "醋醋",
"album": "吴少华",
"cover": "./img/11.png",
"time": "03:43"
},
{
"name": "爱情女神",
"audio_url": "./audios/郭美美 - 爱情女神.ogg",
"singer": "郭美美",
"album": "吴少华",
"cover": "./img/12.png",
"time": "03:36"
}
]