07-Lyric scroll effect

The code work you are studying now may not necessarily be needed. If there is, it has already been made into products and libraries.

What is exercised here is thinking.

Project effect

 Native JS is the most efficient, and the framework only improves the readability of the code

favico icon added

two ways

1. Put it in the root directory of the site, but related to network and deployment, it is not recommended

2. Link introduction

<link rel="shortcut icon" href="./assets//favicon.ico" type="image/x-icon">

audio controls

<audio controls src="./assets//music.mp3"></audio>

rolling principle

 Quickly create lorem (random fake text)

The application of lorem in HTML can generate random text

li*30>lorem4

Set text-align: center for body 

text-align: center is inheritable, body→div→ul→li

Center the content of its line box element horizontally

Control the position of the inner layer ul

Two ideas:

1. margin-top is negative (rendering main thread)

But margin changes will lead to low reflow (rearrangement) performance, which is performed on the main thread

 2. Use JS to control the transform of css3 to realize displacement (synthesis thread)

CSS property changes themselves have no animation effect

The transition transition is for the attributes of the numerical class

When the lyrics are scrolling, the current lyrics are highlighted and enlarged, and are consistent with the position of the progress bar

JS controls which special style, CSS writes the style

Enlarging the fontsize will affect the layout tree, it is best to use transform: scale

Is transition written in li.active or li?

li.active effect disappears without transition effect

So add it to li

 What is the entry point to realize the interface interaction effect?

It's not how to set the attributes of the element, how to monitor the progress of the music player

Instead, start from the data , what data do I have in hand, and convert it into an array or object

var lrc = `[00:01.06]难念的经
[00:03.95]演唱:周华健
[00:06.78]
[00:30.96]笑你我枉花光心计
[00:34.15]爱竞逐镜花那美丽
[00:36.75]怕幸运会转眼远逝
[00:39.32]为贪嗔喜恶怒着迷`;

In this case, what is given is a string, and find a way to turn it into an array

split lyric string

 Ideal effect:

[{time: 1.06, words: '难念的经'}, {time: 3.95, words: '演唱:周华健'}]

Ideas:

  • Split according to the newline character \n, wrap each line into an object
  • Iterate over each object, each object consists of time and lyrics key-value pairs
  • Lyrics time formatting, unified conversion into seconds
/**
 * 解析歌词字符串
 * 得到一个歌词对象的数组
 * 每个歌词对象:
 * {time: 开始时间, words: 歌词内容}
 */
function parseLrc () {
	let lines = lrc.split('\n');
	const result = [];
	for (let i = 0; i < lines.length; i++) {
		let str = lines[i];
		let parts = str.split(']');
		let timeStr = parts[0].substring(1); //从第一项开始截取
		const obj = {
			time: parseTime(timeStr),
			words: parts[1]
		}
		result.push(obj);
	}
	return result;
}
/**
 * 时间字符串转换成秒
 * @param {*} timeStr
 * @returns {Number} 小数
 */
function parseTime (timeStr) {
	let parts = timeStr.split(':');
	return +parts[0] * 60 + +parts[1];
}

The lyrics to be highlighted determines the offset of the ul list

Calculate the number of seconds the current player plays, and the corresponding highlighted lyrics subscript

Get the current playing time
audio.currentTime;
Traverse the lyrics array, judge to find a time greater than the current time, and get the current subscript - 1, which is the corresponding highlighted lyrics subscript

When the data is small, directly appendChild() in ul:

However, if the DOM tree is frequently changed in this way, 70 pieces of data will be changed more than 70 times. The more data, the lower the performance.

function createLrcElements () {
	for (let i = 0; i < lrcData.length; i++) {
		let li = document.createElement('li');
		li.textContent = lrcData[i].words;
		doms.ul.appendChild(li);
	}
}

Never be the first to optimize

Do the code sequence: data logic → interface logic → event

When there is a lot of data:

Utilize document fragment transitions

First insert the li node into createDocumentFragment()

Then add the things in createDocumentFragment to ul

function createLrcElements () {
	const frag = document.createDocumentFragment();
	for (let i = 0; i < lrcData.length; i++) {
		let li = document.createElement('li');
		li.textContent = lrcData[i].words;
		// doms.ul.appendChild(li);
		frag.appendChild(li);
	}
	doms.ul.appendChild(frag);
}

createLrcElements();

let maxOffset = doms.ul.clientHeight - containerHeight;

Set the offset of the ul element

  • When less than the minimum value, let it be equal to 0
  • When greater than the maximum value, it is equal to the maximum value
  • Clear all highlights before highlighting
function setOffset () {
	let index = findIndex();
	let offset = liHeight * index + liHeight / 2 - containerHeight / 2;
	/* 最小值 */
	if (offset < 0) {
		offset = 0;
	}
	/* 最大值 */
	if (offset > maxOffset) {
		offset = maxOffset;
	}
	doms.ul.style.transform = `translateY(-${offset}px)`;
	/* 去掉之前的样式 */
	let li = doms.ul.querySelector('.active');
	if (li) {
		li.classList.remove('active')
	}
	/* 拿到需要高亮的li标签 */
	li = doms.ul.children[index];
	if (li) {
		li.classList.add('active');
	}
}

Guess you like

Origin blog.csdn.net/iaz999/article/details/131363121