原生js实现歌词滚动

216 阅读1分钟

效果

动画.gif

原理

匹配歌曲时间和歌词对象数组,高亮,歌词被容器包裹 一个容器设置overflow:hidden;

包含ul和歌词li,计算ul transform:tranlateY(),移动

方法

  • 初始化
  • 绑定事件

初始化

  • 将获取到的数据,时间和歌词组合变成对象
// 1. 初始化
	async function init() {
		// 拿到歌词,生成li,放入到ul中
		const lrc = await getLrc();
		// 将lrc -> [ { time: 86.09, words: '这沙滚滚水皱皱笑着浪荡' } ....]
		lrcData = lrc
			.split('\n')
			.filter((s) => s)
			.map((s) => {
				const parts = s.split(']');
				const timeParts = parts[0].replace('[', '').split(':');
				return {
					time: +timeParts[0] * 60 + +timeParts[1],
					words: parts[1],
				};
			});
		// 生成li,加入到ul中
		doms.ul.innerHTML = lrcData.map((lrc) => `<li>${lrc.words}</li>`).join('');
	}
  • 初始化常量,行高,容器高度

	const doms = {
		ul: document.querySelector('.lrc'),
		audio: document.querySelector('audio'),
	};
	const size = {
		liHeight: 30,
		containerHeight: 420,
	};
  • 当前歌曲时间匹配对象数组(数组查找第一个数据大于当前事件-1),查找并高亮

歌词高亮 歌词滚动

	/**
	 * 根据播放时间,设置好歌词的状态
	 * @param {*} time
	 */
	function setStatus(time) {
		// 微调
		time += 0.5;
		// 根据时间找到对应的li,高亮
		// 消除之前的active
		const activeLi = document.querySelector('.active');
		activeLi && activeLi.classList.remove('active');
		const index = lrcData.findIndex((lrc) => lrc.time > time) - 1;
		if (index < 0) {
			return;
		}
		doms.ul.children[index].classList.add('active');
		//2. 设置ul的滚动位置
		let top =size.liHeight * index + size.liHeight / 2 - size.containerHeight / 2;
		top = -top;
		if (top > 0) {
			top = 0;
		}
		doms.ul.style.transform = `translateY(${top}px)`;
	}