利用html+css+js 实现网页版音乐播放,支持歌词预览,歌曲上一曲下一曲暂停顺序播放循环播放等功能

先上效果图:

object HTML5网页播放视频默认静音_前端

歌曲部分:

音乐路径为拼接指定路径下的音乐文件url,无需用户手动选取文件路径

歌词部分:

通过ajax获取歌词lyric文本,js解析每句歌词的播放时间和内容

html代码:

<div id="main-section">
        <div id="main-section-1">
          <div class="title-style-1">音乐专区</div>
          <div id="articleContent">
            <div id="typeA" class="animateBorder">
              <div id="titleA" class="titleType">流行音乐</div>
              <ul class="ulSection">
                <li class="liSection">
                  <span class="musicTitle">1.爱在日出前</span>
                  <div id="favMusic" class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">2.醉千年</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">3.晚风作酒</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">4.醒不来的梦</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">5.她的眼睛会唱歌</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">6.秋殇别恋</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">7.半壶纱</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">8.连借口都没有</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">9.百花香</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">10.很任性</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
              </ul>
            </div>

            <div id="typeB" class="animateBorder">
              <div id="titleB" class="titleType">经典老歌</div>
              <ul class="ulSection">
                <li class="liSection">
                  <span class="musicTitle">1.星月神话</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">2.风度</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">3.暗涌</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">4.爱的故事上集</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">5.吴哥窟</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">6.谁在意我留下的泪</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">7.恋人心</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">8.夜曲</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">9.十一年</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">10.断桥残雪</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
              </ul>
            </div>

            <div id="typeC" class="animateBorder">
              <div id="titleC" class="titleType">其它歌曲</div>
              <ul class="ulSection">
                <li class="liSection">
                  <span class="musicTitle">1.想起</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">2.你是风</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">3.乌兰巴托的夜</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">4.The Tower</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">5.家乡</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">6.情非虚构</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">7.我是不是该安静的走开</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">8.曾经心痛</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">9.潮湿的心</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
                <li class="liSection">
                  <span class="musicTitle">10.余情未了</span>
                  <div class="musicStatus" onclick="change(this)"></div>
                </li>
              </ul>
            </div>
          </div>
        </div>

JS代码:

let sectionD1 = document.getElementById("main-section-1");
      let lyricTip = document.getElementById("lyricTip");
      let lyricDisplay = document.getElementById("lyricDisplay");
      let lyricTitle = document.getElementById("lyricTitle");
      let favMusic = document.getElementById("favMusic");
      let progressDiv = document.getElementById("progressDiv");
      let lyricUl = document.getElementById("lyricUl");
      let rollTDiv = document.getElementById("rollTime"); // 实时播放时间Div
      let totalTDiv = document.getElementById("totalTime"); // 总时长时间Div
      let progressBar = document.getElementById("progressBar"); // 歌曲实时进度条
      let progressAni = document.getElementById("progressAni");
      let totalProgress = document.getElementById("totalProgress"); // 歌曲总进度条
      let playType = document.getElementById("playType"); // 播放方式

      let isPlay = false,
        lyricF,
        lines;
      let playTypeNum = 1,
        songID,
        typeNum,
        nowMusic; //控制列表和单曲循环
      let patternType1 = /\[(\d{2}:\d{2}).\d{2}\](.+)/,
        patternType2 = /\[(\d{2}:\d{2}).\d{2}\](.+)/g;
      let linesFadeArr = [],
        linesArr = [],
        timeArr = [],
        lyricArr = []; //歌词处理数字

      //进度条宽度自动布局
      totalProgress.style.width = progressDiv.clientWidth + "px";
      window.addEventListener("resize", function () {
        sectionD1.style.width = "600px";
        totalProgress.style.width = progressDiv.clientWidth + "px";
      });

      let audio = new Audio();
      audio.volume = 0.8;
      change(favMusic);

      function change(t) {
        nowMusic = t;
        linesFadeArr = [];
        linesArr = [];
        timeArr = [];
        lyricArr = [];

        let musicNum = document.querySelectorAll(".musicStatus");

        typeNum = t.parentNode.parentNode.parentNode.children[1].getElementsByTagName("li").length;

        for (i = 0; i < musicNum.length; i++) {
          musicNum[i].style.backgroundImage = "url(./music/play.png)";
        }

        let context = t.parentNode.children[0].innerHTML.replace(/\n/g, "");
        songID = context.replace(/\D/g, "");

        let type = t.parentNode.parentNode.parentNode.id.substr(4, 4);
        let musicSrc = "./music/music" + type + "/" + type + "_" + songID + ".mp3";

        let lyricSrc = "./music/music" + type + "/" + type + "_" + songID + ".lrc";

        audio.src = musicSrc;
        lyricTitle.innerHTML = context.replace(songID, "").replace(".", "");
        t.style.backgroundImage = "url(./music/pause.png)";
        startStop.className = "buttons start";

        //上一曲
        pre.onclick = function () {
          let currentMusicID = songID - 2;
          if (currentMusicID < 0) {
            currentMusicID = typeNum - 1;
          }
          change(t.parentNode.parentNode.children[currentMusicID].children[1]);
        };

        //下一曲
        next.onclick = function () {
          let currentMusicID = songID;
          if (currentMusicID > typeNum - 1) {
            currentMusicID = 0;
          }
          change(t.parentNode.parentNode.children[currentMusicID].children[1]);
        };

        //播放或暂停
        startStop.onclick = function () {
          if (audio.paused) {
            // 如果当前音乐是暂停状态,点击按钮,则改为播放状态
            startStop.className = "buttons start"; // 设置播放的class
            audio.play();
            nowMusic.parentNode.parentNode.children[songID - 1].children[1].style.backgroundImage = "url(./music/pause.png)";
          } else {
            // 如果当前音乐是播放状态,点击按钮,则改为暂停状态
            startStop.className = "buttons stop"; // 设置暂停的class
            audio.pause();
            nowMusic.parentNode.parentNode.children[songID - 1].children[1].style.backgroundImage = "url(./music/play.png)";
          }
        };

        lyricF = fetchItem(lyricSrc);
        if (lyricF == void 0) {
          lyricF = "抱歉,该歌曲暂未找到歌词";
          lyricTip.innerHTML = "抱歉,该歌曲暂未找到歌词";
          lyricTip.style.color = "rgb(9, 226, 161)";
        } else {
          lyricTip.innerHTML = "";
        }
        lines = lyricF.split("\n");
        lyricUl.style.top = 0 + "px";

        //去掉空白行
        for (var i = 0; i < lines.length; i++) {
          if (lines[i].trim() !== "") {
            linesFadeArr.push(lines[i].trim());
          }
        }

        //去掉不含时间行或只包含时间行
        for (var i = 0; i < linesFadeArr.length; i++) {
          if (!patternType1.test(linesFadeArr[i]) || (patternType1.test(linesFadeArr[i]) && linesFadeArr[i].length == 10)) {
            linesFadeArr.splice(i, 1);
          }
        }

        //歌词格式化后最终歌词数组
        for (var i = 0; i < linesFadeArr.length; i++) {
          if (patternType1.test(linesFadeArr[i])) {
            linesArr.push(linesFadeArr[i]);
          }
        }

        //加载歌词
        var lyricText = linesArr.join("\n");
        let tmp = patternType2.exec(lyricText);

        while (tmp) {
          timeArr.push(tmp[1]);
          lyricArr.push(tmp[2]);
          tmp = patternType2.exec(lyricText);
        }

        let str = "";

        lyricArr.forEach((item, index) => {
          str += `<li id="lyricLI" class="${index === 0 ? "active" : ""}" >${item}</li>`;
        });

        lyricUl.innerHTML = str;

        if (isPlay) {
          audio.play();
        } else {
          audio.pause();
          isPlay = true;
          t.style.backgroundImage = "url(./music/play.png)";
          startStop.className = "buttons stop";
        }
      }

      //播放状态处理
      audio.addEventListener("timeupdate", function () {
        var totalTime = audio.duration;
        var currentTime = audio.currentTime;
        if (!isNaN(totalTime)) {
          rollTDiv.textContent = getFormatterDate(currentTime);
          totalTDiv.textContent = getFormatterDate(totalTime);
          var width = Math.floor((currentTime / totalTime) * progressDiv.clientWidth);
          progressBar.setAttribute("style", "width:" + width + "px");
          progressAni.setAttribute("style", "left:" + (width - 2) + "px");
          //当前歌曲播放完毕处理
          if (currentTime == totalTime) {
            let musicStatus = document.querySelectorAll(".musicStatus");

            for (i = 0; i < musicStatus.length; i++) {
              musicStatus[i].style.backgroundImage = "url(./music/play.png)";
            }
            rollTDiv.textContent = "00:00";
            progressBar.setAttribute("style", "width:" + 0 + "px");
            progressAni.setAttribute("style", "left:-2px");
            lyricUl.style.top = 0 + "px";
            startStop.className = "buttons stop";
            if (lyricUl.children[0] != void 0) {
              lyricUl.children[0].className = "active";
            }
            if (playTypeNum == 1) {
              let currentMusicID = songID;
              if (currentMusicID > typeNum - 1) {
                currentMusicID = 0;
              }
              change(nowMusic.parentNode.parentNode.children[currentMusicID].children[1]);
            } else if (playTypeNum == 2) {
              let currentMusicID = songID - 1;
              if (currentMusicID > typeNum - 1) {
                currentMusicID = 0;
              }
              change(nowMusic.parentNode.parentNode.children[currentMusicID].children[1]);
            }
          }
        }

        //歌词渲染
        const minute = parseInt(currentTime / 60);
        const second = parseInt(currentTime % 60);
        const timeStr = (minute < 10 ? "0" + minute : minute) + ":" + (second < 10 ? "0" + second : second);

        const index = timeArr.findIndex((item) => item === timeStr);

        if (index !== -1) {
          //从第7句开始向上移动歌词位置
          if (index > 6) {
            lyricUl.style.top = -(index - 5) * 20 + "px";
            lIndex = index;
          }

          [...lyricUl.children].forEach((item) => (item.className = ""));
          lyricUl.children[index].className = "active";
        }
      });

      //监听进度条点击事件
      totalProgress.addEventListener("click", function (event) {
        updateTime(event.offsetX);
      });
      progressBar.addEventListener("click", function (event) {
        updateTime(event.offsetX);
      });

      function updateTime(x) {
        var totalTime = audio.duration;
        var currentTime = audio.currentTime;
        let actualWidt = progressDiv.clientWidth;
        var selectProgress = x / actualWidt;

        audio.currentTime = totalTime * selectProgress;

        var LWidth = Math.floor(selectProgress * actualWidt);
        progressBar.setAttribute("style", "width:" + LWidth + "px");
        audio.play();
      }

      //ajax获取文本对象
      function fetchItem(url) {
        var item;
        $.ajax({
          type: "get",
          url,
          async: false,
          success: function (data) {
            item = data;
          },
        });
        return item;
      }

      //时间格式化
      function getFormatterDate(time) {
        var m = parseInt(time / 60); // 分
        var s = parseInt(time % 60); // 秒
        // 补零
        m = m > 9 ? m : "0" + m;
        s = s > 9 ? s : "0" + s;
        return m + ":" + s;
      }

      //手动调节音量
      let volumeChange = document.getElementById("volumeChange");
      volumeChange.value = audio.volume * 10;
      volumeChange.onchange = function () {
        var volumeVal = volumeChange.value * 0.1;
        audio.volume = volumeVal;
      };
      let voicIcon = document.getElementById("voicIcon");
      let flag = true;
      volumeChange.style.display = "none";
      voicIcon.onmouseover = function () {
        if (flag) {
          volumeChange.style.display = "";
          flag = false;
        }
      };
      voicIcon.onmouseout = function () {
        setTimeout(function () {
          volumeChange.style.display = "none";
          flag = true;
        }, 3000);
      };

      //鼠标放在进度条显示时间
      var insTime = $("#insTime");
      function showTime(x) {
        var totalTime = audio.duration;
        let actualWidt = progressDiv.clientWidth;
        let nowTime = getFormatterDate((x / actualWidt) * totalTime);
        if (nowTime == "0NaN:0NaN") {
          insTime.text("");
        } else {
          insTime.text(nowTime);
          insTime.css({ left: x - 20 }).fadeIn(0);
        }
      }

      totalProgress.onmouseover = function (event) {
        showTime(event.offsetX);
      };
      progressBar.onmouseover = function (event) {
        showTime(event.offsetX);
      };
      totalProgress.onmouseout = function (event) {
        insTime.text("");
      };
      progressBar.onmouseout = function (event) {
        insTime.text("");
      };

      //播放方式按钮点击事件
      playType.onclick = function () {
        if (playTypeNum == 1) {
          // 当前播放为列表循环,点击切换播放方式时,改为单曲循环
          playTypeNum = 2;
          playType.className = "buttons_dqxh"; // 设置单曲循环的class
        } else {
          // 当前播放为单曲循环,点击切换播放方式时,改为列表循环
          playTypeNum = 1;
          playType.className = "buttons_lbxh"; // 设置列表循环的class
        }
      };

完整代码路径:

https://gitee.com/yueluo9527/web-music-play