代码块中有注释 可以阅读一下 图片和音乐路径不同所以需要自己找一个合适的
播放模式支持:列表播放(默认)、循环播放、随机播放
能控制音量大小、上一曲、下一曲、暂停、播放、播放节奏状态、查看播放列表、删除某条单曲等……功能
顺便封装了个Message的消息提示 状态有(Success、Error、Warning、info)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Music</title>
<style>
* {
box-sizing: border-box;
}
.music_image {
width: 55px;
height: 55px;
}
.music_content {
display: flex;
justify-content: space-between;
}
.music_title {
color: #333;
font-size: 14px;
font-weight: 600;
}
.music_duration {
font-size: 13px;
color: #999;
}
.music_button {
display: flex;
align-items: center;
margin: 0px 20px;
}
.duration_control {
width: 700px;
}
.music_vessel {
display: flex;
justify-content: center;
align-items: center;
padding: 10px 120px;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
.music_up,
.music_play,
.music_pause,
.music_next {
margin: 0 8px;
background-size: 100% 100%;
width: 35px;
height: 35px;
cursor: pointer;
}
.music_up:hover,
.music_play:hover,
.music_pause:hover,
.music_next:hover {
opacity: .3;
}
.music_up {
background-image: url("./icon/up.png");
}
.music_play {
background-image: url("./icon/play.png");
}
.music_pause {
background-image: url("./icon/pause.png");
display: none;
}
.music_next {
background-image: url("./icon/next.png");
}
.music_audio {
display: none;
}
#range {
cursor: pointer;
}
.music_mode {
display: flex;
width: 100px;
justify-content: space-between;
margin: 0 20px;
position: relative;
}
.music_lists {
position: absolute;
right: 0;
width: 400px;
height: 0px;
bottom: 35px;
border-radius: 8px;
background-color: rgb(243, 243, 243);
z-index: 2;
display: none;
transition: all .3s;
overflow-y: scroll;
overflow-x: hidden;
padding: 10px;
}
/* .music_lists>div {
width: 100%;
height: 500px;
border: 1px solid #000;
} */
.music_lists>.lists {
width: 100%;
max-height: 300px;
min-height: 300px;
}
.music_lists>.info {
cursor: pointer;
padding: 10px;
margin-bottom: 5px;
display: flex;
justify-content: space-between;
font-size: 13px;
align-items: center;
border-radius: 5px;
}
.music_lists>.info:hover {
background-color: #fff;
}
.music_lists>.active {
font-weight: 600;
color: #149ce6;
background-color: #fff;
}
.music_lists>.info>.music_list_index {
margin-right: 10px;
}
.music_lists>.info>.music_list_title {
width: 90%;
}
.music_lists>.info>.music_list_delete {
width: 18px;
height: 18px;
background: url("icon/delete.png") no-repeat;
background-size: 100% 100%;
}
.music_lists>.info>.music_list_delete:hover {
opacity: 0.5;
}
.music_lists::-webkit-scrollbar {
width: 10px;
}
.music_lists::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 5px;
background: #b8b7b7;
}
.music_lists::-webkit-scrollbar-track {
/*滚动条里面轨道*/
border-radius: 10px;
background: transparent;
}
.volume_control {
position: absolute;
right: 17px;
bottom: 95px;
transform: rotate(-90deg);
background-color: rgb(243, 243, 243);
border-radius: 8px;
padding: 0 5px;
z-index: 1;
display: none;
}
.volume_range {
cursor: pointer;
}
.play_mode,
.music_list,
.volume {
width: 25px;
height: 25px;
background-size: 100% 100%;
cursor: pointer;
/* border:1px solid #000; */
}
.playing {
display: flex;
align-items: flex-end;
height: 10px;
}
.playing .side1,
.playing .side2,
.playing .side3 {
width: 2px;
background-color: #149ce6;
margin-left: 2px;
}
.playing .side1 {
height: 6px;
animation: playingSide1 1.2s linear infinite;
}
.playing .side2 {
height: 4px;
animation: playingSide2 1.2s linear infinite;
}
.playing .side3 {
height: 10px;
animation: playingSide3 1.2s linear infinite;
}
.play_mode {
background-image: url("icon/cycle.png");
}
.volume {
background-image: url("icon/volume.png");
}
.music_list {
background-image: url("icon/list.png");
background-size: 90% 90%;
background-repeat: no-repeat;
background-position: center bottom;
}
@keyframes musicListShow {
0% {
height: 0px;
display: none;
overflow-y: hidden;
}
100% {
height: 300px;
display: block;
overflow-y: hidden;
}
}
@keyframes musicListHidden {
0% {
height: 300px;
display: block;
}
100% {
height: 0px;
display: none;
}
}
@keyframes playingSide1 {
0% {
height: 6px;
}
56% {
height: 10px;
}
100% {
height: 8px;
}
}
@keyframes playingSide2 {
0% {
height: 4px;
}
28% {
height: 6px;
}
80% {
height: 12px;
}
100% {
height: 6px;
}
}
@keyframes playingSide3 {
0% {
height: 10px;
}
56% {
height: 8px;
}
100% {
height: 6px;
}
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<div class="music_vessel">
<!-- 默认音乐图片填充 -->
<img src="./icon/music.png" class="music_image">
<!-- 操作按钮 -->
<div class="music_button">
<!-- 上一首 -->
<div class="music_up"></div>
<!-- 播放 -->
<div class="music_play"></div>
<!-- 暂停 -->
<div class="music_pause"></div>
<!-- 下一首 -->
<div class="music_next"></div>
</div>
<div class="music_info">
<!-- 显示时长 -->
<div class="music_content">
<span class="music_title">
你好世界,欢迎收听你的月亮我的心!
</span>
<span class="music_duration">
0:00 / 0:00
</span>
</div>
<!-- 时长控制 -->
<input type="range" id="range" class="duration_control" value="0" disabled>
</div>
<div class="music_mode">
<!-- 音量 -->
<div class="volume"></div>
<div class="volume_control">
<input type="range" class="volume_range" value="100" max="100">
</div>
<!-- 播放模式 -->
<div class="play_mode"></div>
<!-- 播放列表 -->
<div class="music_list"></div>
<div class="music_lists">
</div>
</div>
</div>
<audio src="" class="music_audio"></audio>
</body>
<script>
// 获取DOM元素
const $ = Dom => document.querySelector(Dom);
const class$ = Dom => document.querySelectorAll(Dom);
const volumeBtn = $(".volume"); //音量按钮
const musicListBtn = $(".music_list"); //列表按钮
const musicListsBox = $(".music_lists");//列表显示容器
const musicAudio = $(".music_audio"); //重中之重 音乐控件
const musicTitle = $(".music_title"); //音乐标题
const musicUp = $(".music_up"); // 上一首
const musicDuration = $(".music_duration"); // 时长显示
const durationControl = $(".duration_control"); //时长控制
const musicPlay = $(".music_play") // 播放
const musicPause = $(".music_pause")// 暂停
const musicNext = $(".music_next") // 下一首
let activePlay = -1; // 当前播放的那一首
let playModeStatus = "cycle"; //播放模式 (默认)cycle:列表循环 oneCycle:单曲循环 random:随机播放
const playModeStatusObj = {
cycle: "oneCycle",
oneCycle: "random",
random: "cycle",
}
const musicList = [
{ title: "万能青年旅店 - sha死那个石家庄人", url: "./audio/万能青年旅店 - sha死那个石家庄人.mp3" },
{ title: "隔壁老樊 - 姬和不如", url: "./audio/隔壁老樊 - 姬和不如.flac" },
{ title: "宋冬野 - 安和桥", url: "./audio/宋冬野 - 安和桥.flac" },
{ title: "宋冬野 - 董小姐", url: "./audio/宋冬野 - 董小姐.flac" },
{ title: "Ayo97 周思涵 - 感谢你曾来过", url: "./audio/Ayo97 周思涵 - 感谢你曾来过.mp3" },
{ title: "队长 - 哪里都是你", url: "./audio/队长 - 哪里都是你.flac" },
{ title: "C.HØPE - 沉沦与遐想", url: "./audio/C.HØPE - 沉沦与遐想.mp3" },
{ title: "Copy,BT07 - 晚风", url: "./audio/Copy,BT07 - 晚风.mp3" },
{ title: "Round_2 - Kill The Game", url: "./audio/Round_2 - Kill The Game.mp3" },
// { title: "艾福杰尼 - Yellow Skin Flow", url: "./audio/艾福杰尼 - Yellow Skin Flow.ape" },
{ title: "烟把儿乐队 - 纸短情长", url: "./audio/烟把儿乐队 - 纸短情长.mp3" },
{ title: "周杰伦 - 以父之名", url: "./audio/周杰伦 - 以父之名.flac" },
] //音乐播放列表
// 消息提醒
const message = (messageInfo) => {
let messageStatus = {
success: {
color: "#67C23A",
backgroundColor: "#F0F9EB"
},
warning: {
color: "#E6A23C",
backgroundColor: "#FDF6EC"
},
error: {
color: "#F56C6C",
backgroundColor: "#FEF0F0"
},
}
let messageDom = document.createElement("div");
let keepTime = messageInfo.keepTime || 1500
messageDom.innerText = messageInfo.message || ""
let messageStyle = {
color: "#909399",
backgroundColor: "#EDF2FC",
position: "fixed",
top: "-20%",
left: "50%",
transform: "translate(-50% , 0)",
width: "420px",
borderRadius: "5px",
boxSizing: "border-box",
padding: "15px 20px",
transition: "all 0.6s",
};
if (messageInfo.type) {
messageStyle.color = messageStatus[messageInfo.type].color;
messageStyle.backgroundColor = messageStatus[messageInfo.type].backgroundColor;
}
for (let styleKey in messageStyle) {
messageDom.style[styleKey] = messageStyle[styleKey];
}
document.body.appendChild(messageDom)
setTimeout(() => {
messageDom.style['top'] = "10%";
})
setTimeout(() => {
messageDom.style['top'] = "-20%"
setTimeout(() => {
messageDom.remove()
}, 600)
}, keepTime)
}
// 渲染播放列表
const createMusicList = () => {
let musicListHtml = "";
// <div class="music_list_index">${index + 1}< /div>
musicList.forEach((el, index) => {
musicListHtml += `
<div class="info ${activePlay == index ? 'active' : ''}" data-index="${index}">
<div class="music_list_index">
${activePlay == index ?
`<div class="playing">
<div class="side1"></div>
<div class="side2"></div>
<div class="side3"></div>
</div>`
: index + 1}
</div>
<div class="music_list_title">${el.title}</div>
<div class="music_list_delete" data-index="${index}"></div>
</div>`
})
musicListsBox.innerHTML = musicListHtml;
// 点击播放
class$(".info").forEach((dom_el) => {
dom_el.onclick = (e) => {
activePlay = dom_el.dataset['index'];
initialize();
}
})
//
class$(".music_list_delete").forEach((dom_el) => {
dom_el.onclick = (e) => {
e.stopPropagation();
musicList.splice(dom_el.dataset['index'], 1);
if (activePlay == dom_el.dataset['index']) {
activePlay--;
initialize();
}
createMusicList()
}
})
}
// 播放模式控制
$(".play_mode").onclick = (e) => {
playModeStatus = playModeStatusObj[playModeStatus];
$(".play_mode").style.backgroundImage = `url("icon/${playModeStatus}.png")`;
}
// 音量按钮
volumeBtn.onclick = (e) => {
$(".volume_control").style.display == "block" ? $(".volume_control").style.display = "none" : $(".volume_control").style.display = "block";
}
// 控制音量
$(".volume_control").children[0].onchange = (e) => {
musicAudio.volume = $(".volume_control").children[0].value / 100
}
// 列表点击事件
musicListBtn.onclick = (e) => {
musicListsBox.style.animation == "musicListShow .3s linear" ? musicListsBox.style.animation = "musicListHidden .3s linear" : musicListsBox.style.animation = "musicListShow .3s linear"
setTimeout(() => {
musicListsBox.style.display == 'block' ? (musicListsBox.style.display = "none") : (musicListsBox.style.display = "block")
}, 300)
musicListsBox.style.height == '300px' ? (musicListsBox.style.height = "0px") : (musicListsBox.style.height = "300px")
createMusicList()
}
//播放模式 (默认)cycle:列表循环 oneCycle:单曲循环 random:随机播放
// 上一首
musicUp.onclick = (e) => {
if (activePlay === 0 && playModeStatus != "random") {
message({ type: "warning", message: "已经是第一首了" })
return;
}
if (activePlay !== -1 && playModeStatus != "random") {
activePlay--;
}
if (playModeStatus == 'random') {
activePlay = Math.floor(Math.random() * 11);
}
initialize();
}
// 下一首
musicNext.onclick = (e) => {
if (musicList.length == 0) {
message({ type: "error", message: "播放列表中暂无歌曲" });
return;
}
if (activePlay == musicList.length - 1 && playModeStatus != "random") {
activePlay = 0;
initialize();
return;
}
if (activePlay !== -1 && playModeStatus != "random") {
activePlay++;
}
if (playModeStatus == 'random') {
activePlay = Math.floor(Math.random() * 11);
}
initialize();
}
// 渲染音频
const initialize = () => {
if (musicList.length == 0) {
message({ type: "error", message: "播放列表中暂无歌曲" });
musicTitle.innerText = "你好世界,欢迎收听你的月亮我的心!";
musicAudio.src = "";
durationControl.disabled = true;
durationControl.value = 0;
return;
}
if (activePlay === -1) {
activePlay = 0;
}
createMusicList()
musicTitle.innerText = musicList[activePlay].title;
musicAudio.src = musicList[activePlay].url;
durationControl.disabled = false;
musicAudio.play();
}
// 时长控制器状态值发生改变时
durationControl.onchange = (e) => {
musicAudio.currentTime = durationControl.value;
}
// 歌曲开始播放时
musicAudio.onplay = (e) => {
musicPlay.style.display = "none";
musicPause.style.display = "block";
[...$(".playing").children].forEach(el => el.style.animationPlayState = "")
}
// 歌曲暂停时
musicAudio.onpause = (e) => {
musicPlay.style.display = "block";
musicPause.style.display = "none";
[...$(".playing").children].forEach(el => el.style.animationPlayState = "paused")
}
// 歌曲播放结束时
musicAudio.onended = (e) => {
musicPlay.style.display = "block";
musicPause.style.display = "none";
if (playModeStatus == "oneCycle") {
musicAudio.play()
return;
}
if (activePlay == musicList.length - 1 && playModeStatus == "cycle") {
activePlay = 0;
initialize();
return;
}
if (activePlay != musicList.length - 1 && playModeStatus != "oneCycle") {
activePlay++;
}
if (playModeStatus == 'random') {
activePlay = Math.floor(Math.random() * 11);
}
initialize();
}
// 时长更改时会执行
musicAudio.ontimeupdate = (e) => {
if (musicAudio.currentTime >= 0 && musicAudio.duration >= 0) {
let totalF = parseInt(musicAudio.duration / 60); //总时长 分钟
let totalM = parseInt(musicAudio.duration % 60); //总时长 秒数
let currentF = parseInt(musicAudio.currentTime / 60);
let currentM = parseInt(musicAudio.currentTime % 60) < 10 ? '0' + parseInt(musicAudio.currentTime % 60) : parseInt(musicAudio.currentTime % 60);
musicDuration.innerHTML = ` ${currentF}:${currentM} / ${totalF}:${totalM}`;
durationControl.max = musicAudio.duration;
durationControl.value = musicAudio.currentTime;
}
}
// 开始播放
musicPlay.onclick = (e) => {
if (activePlay !== -1) {
musicAudio.play();
return;
}
initialize()
}
musicPause.onclick = (e) => {
musicAudio.pause();
}
</script>
</html>