前端实践-歌词滚动效果 | 豆包MarsCode AI 刷题

358 阅读3分钟

前言

在很多音乐播放平台,都会有音频播放器和歌词同步显示功能,本文将介绍如何利用纯前端的方法实现歌词滚动效果。

image.png

1. 解析歌词数据

通常,歌词数据的存储格式为 .lrc 文件,它包含了歌词的时间戳和对应的歌词内容。

通过解析这些数据,我们可以得到歌词对象。

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 obj = {
      time: parseTime(timeStr),
      words: parts[1],
    };
    result.push(obj);
  }
  return result;
}

function parseTime(timeStr) {
  var parts = timeStr.split(':');
  return +parts[0] * 60 + +parts[1];
}

在这段代码中,我们通过 parseLrc 这个函数解析歌词字符串,获取每一句歌词的开始时间和歌词内容。

然后再使用 parseTime 这个函数将时间字符串被转换为秒数,便于后续的时间比对。

2. 显示歌词

下一步,我们需要把这些歌词元素渲染到网页上。

我们可以遍历解析每条歌词数据,为每一句歌词创建一个 li 元素,并将其添加到外面的 ul 列表中。

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);
  }
  doms.ul.appendChild(frag);
}

3. 根据当前播放时间计算歌词滚动

根据音频播放的时间来动态调整歌词的显示位置。

每当播放器的时间发生变化时,我们需要计算当前播放到哪一秒,进而找到应该高亮显示的歌词行。

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;
}

4. 设置歌词滚动偏移量

为了后续实现滚动效果,我们需要计算出歌词列表 (ul) 的偏移量,使得当前播放的歌词行位于视口的中央。

通过计算当前歌词行的索引,我们可以设置 ul 元素的 transform 属性来实现滚动。

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)`;
  
  // 高亮当前歌词
  var li = doms.ul.querySelector('.active');
  if (li) {
    li.classList.remove('active');
  }
  li = doms.ul.children[index];
  if (li) {
    li.classList.add('active');
  }
}

此函数的作用是根据计算的偏移量设置 ul 元素的 translateY 值,从而使歌词内容随音频进度滚动。

同时,添加上 active 类来高亮显示当前正在播放的歌词行。

5. 设置样式

为了使歌词滚动效果更为流畅,我们需要通过 CSS 来控制歌词的外观和滚动动画。

设置容器的高度、溢出隐藏和滚动动画,以及为当前歌词行设置高亮样式。

* {
  margin: 0;
  padding: 0;
}

body {
  background: #000;
  color: #666;
  text-align: center;
}

audio {
  width: 450px;
  margin: 30px 0;
}

.container {
  height: 420px;
  overflow: hidden;
}

.container ul {
  transition: 0.6s;
  list-style: none;
}

.container li {
  height: 30px;
  line-height: 30px;
  transition: 0.2s;
}

.container li.active {
  color: #fff;
  transform: scale(1.2);
}

这里,我们使用 transition 属性来使歌词滚动和高亮切换更为平滑。

6. 函数调用

给音频绑定 timeupdate 事件,调用 setOffset 函数,使得歌词能够随着音频的播放实时滚动。

doms.audio.addEventListener('timeupdate', setOffset);