JS实现一个简单的音乐播放器和歌词滚动效果| 青训营

1,897 阅读1分钟

先上图:

图片.png

原理

一个audio标签,一个歌曲文件和一个歌词文件,然后就是JS控制歌词滚动逻辑和界面布局

听起来十分简单,但是,真正要不借助任何框架做出来才知道还是挺考验基础功的

1、页面布局

要有一个audio音乐播放标签,和一个歌词容器,然后引入样式表、歌词js文件和主逻辑js文件

<div class="app">
        <!-- 音乐播放器 -->
        <audio src="./src/雲翼星辰 - 黑暗森林.mp3" controls></audio>
        <!-- 歌词 -->
        <div class="container">
            <ul class="lrc_list"></ul>
        </div>
    </div>
    <script src="./lrc.js"></script>
    <script src="./index.js"></script>

2、拿到歌曲和歌词

随便下载一个歌曲文件和一个歌词文件,歌词文件格式为 .lrc,打开之后,复制到 lrc.js 文件中,然后定义一个全局变量var lrc = 'xxxx',方便我们使用

图片.png

歌词格式,就是一段字符串,但是,字符串不方便操作,因此需要转换为js对象:

function parseLrc() {
    var lines = lrc.split('\n');
    var result = []; // 歌词对象数组
    for (var i = 0; i < lines.length; i++) {
      var str = lines[i];
      var parts = str.split(']');
      var timeStr = parts[0].substring(1);
      var parts = timeStr.split(':');
      var obj = {
        time: +parts[0] * 60 + +parts[1],
        words: parts[1],
      };
      result.push(obj);
    }
    return result;
  }
  

得到的是一个对象数组,有时间和对应的文字:

图片.png

3、获取对应的DOM

为方便管理,把dom都封装到一个对象中

//歌词对象
var lrcData = parseLrc();
  // 获取需要的 dom
var doms = {
    audio: document.querySelector('audio'),
    ul: document.querySelector('.lrc_list'),
    container: document.querySelector('.container'),
  };

4、获取播放器时间对应的歌词

function findIndex() {
    // 播放器当前时间
    var curTime = doms.audio.currentTime;
    for (var i = 0; i < lrcData.length; i++) {
      if (curTime < lrcData[i].time) {
        return i - 1;
      }
    }
    // 找遍了都没找到(说明播放到最后一句)
    return lrcData.length - 1;
  }

获取当前播放器的时间,然后返回对应时间的歌词

5、创建歌词元素 li

使用js根据歌词对象,为每句歌词动态地创建li元素

function createLrcElements() {
    var frag = document.createDocumentFragment(); // 文档片段
    for (var i = 0; i < lrcData.length; i++) {
      var li = document.createElement('li');
      li.textContent = lrcData[i].words;
      frag.appendChild(li); // 改动了 dom 树
    }
    doms.ul.appendChild(frag);
  }
createLrcElements();

6、计算歌词偏移

播放的歌词会添加一个特殊样式,放大且字体为白色,需要动态添加,最后添加音乐播放标签的播放时间事件,根据播放时间,计算歌词元素滚动的偏移量

// 容器高度
var containerHeight = doms.container.clientHeight;
// 每个 li 的高度
var liHeight = doms.ul.children[0].clientHeight;
// 最大偏移量
var maxOffset = doms.ul.clientHeight - containerHeight;
// 设置偏移
function setOffset() {
    var index = findIndex();
    var offset = liHeight * index + liHeight / 2 - containerHeight / 2;
    if (offset < 0) {
      offset = 0;
    }
    if (offset > maxOffset) {
      offset = maxOffset;
    }
    doms.ul.style.transform = `translateY(-${offset}px)`;
    // 去掉之前的 active 样式
    var li = doms.ul.querySelector('.active');
    if (li) {
      li.classList.remove('active');
    }
    li = doms.ul.children[index];
    if (li) {
     li.classList.add('active');
    }
  }
  doms.audio.addEventListener('timeupdate', setOffset);