纯前端语言编写音乐播放器
app效果图:
播放器实现的功能
- 列表点击播放
- 自动循环播放
- 上一首
- 下一首
- 暂停、继续
- 随机播放
- 单曲循环
本文的音乐资源
http://www.softeem.xin:8888/public/musicData/musicData.json
下面这些按钮是导入了字体图标库font-awesome 4.7.0 ,需要自己引入
html代码
<html> <head> <!-- 对于需要在移动终端中显示的页面需要添加如下配置 --> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <meta charset="utf-8" /> <title>爱音乐</title> <!-- 引入核心样式文件 --> <link rel="stylesheet" href="./css/index.css"> <!-- 导入字体图标库font-awesome 4.7.0 --> <link rel="stylesheet" href="./res/font-awesome-4.7.0/css/font-awesome.css"> </head> <body> <!-- emmet - PHP --> <div id="app" class="verticle"> <!-- header区域布局 --> <div class="header center"> <img src="./img/20201124032511.png" alt=""> </div> <!-- body区域布局 --> <div class="body verticle"> <!-- 当前播放的歌曲名 --> <div class="playing_music_name center">爱音乐</div> <!-- 唱片结构 --> <div class="cover-disc center "> <img src="img/img01.jpg" alt=""> </div> <div class="playing_music_name text center">快在列表中选择一首歌吧</div> </div> <!-- footer区域布局 --> <div class="footer verticle"> <!-- 进度条触摸区域 --> <div class="progress-box"> <!-- 进度条背景 --> <div class="progress-bg"> <!-- 实际播放进度 --> <div class="progress"> <!-- 滑块 --> <div class="thumb"></div> </div> </div> </div> <!-- 播放时间显示区域 --> <div class="time horizontal"> <div class="time-now"></div> <div class="time-total"></div> </div> <!-- 歌曲播放控制区域 --> <div class="controls horizontal"> <button class="btn-loop-type"> <i class="fa fa-random"></i> </button> <button class="btn-prev"> <i class="fa fa-fast-backward fa-2x"></i> </button> <button class="btn-play-pause"> <i class="fa fa-pause-circle-o fa-4x"></i> </button> <button class="btn-next"> <i class="fa fa-fast-forward fa-2x"></i> </button> <button class="btn-music-list"> <i class="fa fa-list-ul"></i> </button> </div> </div> </div> <!-- 悬浮框歌曲列表层,默认隐藏 --> <div class="music-list-container"> <!-- 关闭按钮 --> <button class="btn-close"> <i class="fa fa-times-circle-o fa-2x "></i> </button> <div class="music-list"> <ul> <li>孤勇者01</li> <li>孤勇者02</li> <li>孤勇者03</li> </ul> </div> </div> <!-- 引入js脚本 --> <script src="./js/index.js"></script> </body> </html>
css代码
*{ margin:0; padding: 0; } /* 弹性布局(垂直) */ .verticle{ display: flex; flex-direction: column; } /* 弹性布局(水平) */ .horizontal{ display: flex; flex-direction: row; } #app{ width:100vw; height:100vh; background:linear-gradient(135deg, #ed2f6d, #85bdd8); } /* header区域样式 */ .header{ flex:1; } .header>img{ height: 3rem; /* 1rex=16px */ } .center{ display:flex; align-items: center; justify-content: center; } /* body区域样式 */ .body{ flex:8; background: #eee; } .playing_music_name{ flex:1; font-size: 1.2rem; letter-spacing: 2px; color: #3498db; } .cover-disc{ flex:6; background: url('../img/disc.png') no-repeat center center; /* 动画 */ animation: cycler 5s infinite linear; animation-play-state:paused; } /* 执行动画 */ .playing{ animation-play-state: running; } .cover-disc>img{ width: 50%; border-radius: 50%; } /* footer区域样式 */ .footer{ flex:2; } .progress-box{ flex:1; } .progress-bg{ height: 2px; background: #fff; } .progress{ /* 子绝父相 */ position: relative; height: 100%; width: 0%; background: #ff6700; } .thumb{ position: absolute; right: -5px; top: -6px; width: 6px; height: 6px; border:4px solid #fff; text-align: center; background: #ff6700; border-radius: 50%; box-shadow: 0 0 20px #ff6700; } .time{ flex:1; } .time>div{ padding:0 5px; flex:1; color:#fff; } .time-total{ text-align: right; } .controls{ flex:5; } .controls>button{ background: transparent; border: 0; color: #fff; } .btn-loop-type, .btn-music-list{ flex: 1; } .btn-prev, .btn-next{ flex: 2; } .btn-play-pause{ flex: 3; } /* 自定义旋转动画 */ @keyframes cycler{ from{ transform:rotate(0deg); } to{ transform:rotate(360deg); } } /*歌曲列表悬浮层样式*/ .music-list-container{ position: absolute; left:0; right:0; bottom:0; top:10rem; z-index: 99999; /*层叠*/ background: rgba(0,0,0,0.5); display: none; /*初始隐藏悬浮层*/ overflow-y: scroll;/*纵轴方向如果内容溢出,则滚动显示*/ } .btn-close{ position: fixed; top:10.25rem; right: 0.25rem; z-index: 1; color:#fff; /*设置字体图标颜色*/ border:0; /*去除按钮边框*/ background: transparent;/*去除按钮的背景色*/ } .music-list{ padding:0.5rem; color:#eee; font-size: 1.2rem; } .music-list li{ padding:0.8rem 0; } .music-list li:hover, .playing-holder{ color:#ff6700; background: rgba(255,255,255,0.5); } .music-list li:not(:last-child){ /* 设置选中元素的下边框 */ border-bottom: 1px solid rgba(255,255,255,0.5); }
js代码
//自调用函数 (function() { //歌曲列表api接口 const Base_url = 'http://www.softeem.xin:8888/public/musicData/' const Music_url = Base_url + 'musicData.json' //声明媒体播放器对象 var player = document.createElement('audio'); //定义数组对象存储所有的歌曲 var musics = []; //记录当前播放的歌曲索引 var currentIndex = 0; //播放器的当前进度和总进度 var now = 0; var total = 0; //歌曲播放状态 var isPlay = false; //歌曲状态 0-列表 1-随机 2-单曲循环 var loopType = 0; // 实现点击歌曲列表的显示 document.querySelector('.btn-music-list').onclick = function() { document.querySelector('.music-list-container').style.display = 'block' } document.querySelector('.btn-close').onclick = function() { document.querySelector('.music-list-container').style.display = 'none' } //请求远程服务器,获取服务端提供的歌曲信息 //创建XMLHttoRequest对象(java中与服务端交互对象) var xhr = new XMLHttpRequest(); //打开连接 xhr.open('GET', Music_url); //发送请求 xhr.send(null); //当准备状态发生变化时执行回调 xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { var data = xhr.responseText; //将json字符串解析为js对象 musics = JSON.parse(data); var html = ''; //i是索引,m是歌曲 musics.forEach((m, i) => { //每读取到一条数据创建一个dom节点 html += `<li data-index="${i}" >${m.musicName}</li>`; }) document.querySelector('.music-list>ul').innerHTML = html; } } //为列表项绑定点击事件,播放音乐(事件委托) document.querySelector('.music-list>ul').onclick = function(e) { document.querySelectorAll('.music-list li')[currentIndex].className = ''; //获取真实被点击的目标元素 currentIndex = e.target.dataset.index; var m = musics[currentIndex]; var url = Base_url + m.musicPath; player.src = url; document.querySelector('.text').innerText = ""; startPlay(m); } function startPlay(m) { //播放 var music_play = player.play(); if (music_play) { music_play.then(() => { // 音乐加载成功 isPlay = true; // 播放需要耗时 setTimeout(() => { // 后续操作 console.log("done."); }, total.duration * 1000); // total.duration 为音乐的时长,单位为秒 }).catch((e) => { // 加载失败 }) } //显示歌曲名 document.querySelector('.playing_music_name').innerText = m.musicName; //唱片图片更新 document.querySelector('.cover-disc>img').src = Base_url + m.picPath; //唱片旋转 document.querySelector('.cover-disc').className = 'cover-disc center playing'; //设置正在播放的歌曲的高亮 document.querySelectorAll('.music-list li')[currentIndex].className = 'playing-holder'; } //为播放器对象绑定歌曲的第一帧加载完成事件 player.addEventListener('loadeddata', function() { //获取歌曲总时长 total = player.duration; document.querySelector('.time-total').innerText = formaTime(total); }) player.addEventListener('timeupdate', function() { now = player.currentTime; //计算进度条 var progress = now / total * 100 + '%'; document.querySelector('.progress').style.width = progress; document.querySelector('.time-now').innerText = formaTime(now); }) function formaTime(time) { //以毫秒为基础创建日期对象 time = new Date(time * 1000); var m = time.getMinutes(); var s = time.getSeconds(); m = m < 10 ? '0' + m : m; s = s < 10 ? '0' + s : s; return m + ':' + s; } //播放暂停按钮绑定单击事件 document.querySelector('.btn-play-pause').onclick = function() { if (isPlay) { //暂停 player.pause(); //唱片停止旋转 document.querySelector('.cover-disc').className = 'cover-disc center'; //更改按钮图标 this.innerHTML = '<i class="fa fa-play-circle-o fa-4x"></i>'; isPlay = false; } else { startPlay(musics[currentIndex]); this.innerHTML = '<i class="fa fa-pause-circle-o fa-4x"></i>'; } } document.querySelector('.btn-loop-type').onclick = function() { //loopType始终在0-2之间 loopType = ++loopType % 3; var t=""; if (loopType == 0) { //列表 t="列表循环"; this.innerHTML = '<i class="fa fa-list-ol"></i>'; } else if (loopType == 1) { //随机 t="随机循环"; this.innerHTML = '<i class="fa fa-random"></i>'; } else { //单曲 t="单曲循环"; this.innerHTML = '<i class="fa fa-repeat"></i>'; } document.querySelector('.text').innerText = t; } function nextMusic() { if (currentIndex != -1) { document.querySelectorAll('.music-list li')[currentIndex].className = ''; } if (loopType == 0) { //列表 currentIndex++; if (currentIndex >= musics.length) currentIndex = 0; } else if (loopType == 1) { //随机 currentIndex = parseInt(Math.random() * musics.length); } //由于单曲循环无需修改索引,因此不作处理 player.src = Base_url + musics[currentIndex].musicPath; startPlay(musics[currentIndex]) } function prevMusic() { if (currentIndex != -1) { document.querySelectorAll('.music-list li')[currentIndex].className = ''; } if (loopType == 0) { //列表循环 currentIndex--; if (currentIndex <= 0) currentIndex = musics.length - 1; } else if (loopType == 1) { //随机循环 currentIndex = parseInt(Math.random() * musics.length); } player.src = Base_url + musics[currentIndex].musicPath; startPlay(musics[currentIndex]) } //滑动进度条 document.querySelector('.progress-box').onclick = function(e) { var n=(e.clientX/document.body.clientWidth)*100+'%'; document.querySelector('.progress').style.width = n; player.currentTime=(e.clientX/document.body.clientWidth)*total; } document.querySelector('.btn-prev').onclick = prevMusic; document.querySelector('.btn-next').onclick = nextMusic; //歌曲播放完自动下一首 player.addEventListener('ended', nextMusic); })();