js歌词逐字滚动效果

@Null - 滨

先上效果图

目录结构:

歌词文本music.txt
将酷狗歌词KRC用“酷狗歌词(krc)加解密工具”进行解密后可以得到这种歌词文本


HTML代码

<!DOCTYPE html>
<html lang="en">
<head><!-- 网页图标 --><link rel="icon" href="data:image/png;base64,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"><meta charset="UTF-8"><title>Music</title><!-- 引入css文件 --><link rel="stylesheet" href="./code.css">
</head>
<body>
<canvas id="canvas">浏览器不支持Canvas,请升级浏览器!</canvas>
<audio controls id="myAudio" preload src="./music/music.mp3">当前浏览器不支持播放音频</audio>
<div class="music"><div class="songInfo"><p id="songName"></p><p id="singerName"></p></div><div class="player"><img class="animation" id="img" src="./images/cover.jpg"><a class="btn" href="javascript:" id="btn" onclick="play_pause()"></a></div><div class="lrc_box"><div class="lrc" id="lrc"><p class="blank"></p></div></div>
</div>
<div class="control"><p><a class="btn" href="javascript:" id="btn2" onclick="play_pause()"></a></p><div class="time_progressBar"><div class="time"><p class="currentTime" id="currentTime">00:00</p><p>/</p><p class="duration" id="duration">00:00</p></div><div class="progressBar" id="progressBar"><p class="progress" id="progress"></p></div></div><div class="volume" id="volume"><div class="volumeBox" id="volumeBox"><div class="volumeBar" id="volumeBar"><p class="currentVolume" id="currentVolume"></p></div><div class="volumeText"><span id="currentVolumeText">0</span><span>%</span></div></div><div id="volumeBtn"><!-- 音量按钮svg图标 --><svg class="svg" height="26" viewBox="0 0 1080 1080" width="26"><path class="path"d="M541.2 132.3c-7.2-3.3-15.2-5-23.3-5-13.9 0-26.8 5.1-36.5 14.4L280.6 312.4h-158c-11.5 0-23.9 3.9-33.6 10.4h-4l-8.7 9.2c-7.5 7.9-12.2 20.8-12.2 33.8v290.7c0 15 6.7 31.4 16.9 41.6 10.2 10.3 26.6 16.9 41.6 16.9h158.2l200.7 165.6c8.4 7.9 23.3 16 35.6 16 5.6 0 16.5 0 27.1-8 10-4.2 17.8-10.4 23.1-18.6 5.7-8.6 8.4-19.1 8.4-32V184c0-12.9-2.8-23.4-8.4-32-5.8-9-14.6-15.6-26.1-19.7z m-24.8 57.4v642.9L310.2 662.5l-8.2-6.8v0.1H123.3V371.7h179l214.1-182z"id="volumeIcon"></path><path class="path"d="M752.7 376.7c-23.8-27.4-48.4-40.2-53.7-42.1h-1.6l-1.9-1.3c-3.2-2.2-7.4-3.3-12-3.3-11.9 0-24.9 7.6-27.8 16.4l-0.3 1-0.6 0.9c-3.8 5.8-4.3 14.2-1.4 22.7 2.9 8.4 8.6 15.1 14.6 17.1l0.6 0.2 0.6 0.3c0.7 0.4 17.2 9.5 33.6 29.7 15.1 18.5 33.1 50.3 33.1 96.7 0 96.6-54.4 128.5-60.7 131.9-13.8 9.4-23 27.9-14.6 40.4l0.3 0.4 0.2 0.5c4.3 8.7 18.9 18.6 27.3 18.6 5.5 0 8.4-0.1 11.7-3.8l2.2-2.2H704.7c6.2-2.3 28.7-15.6 50.6-44.2 20.6-26.9 45.1-74.4 45.1-147.4 0-64.2-25.9-107.5-47.7-132.5z"id="volume_1_icon"style="display:inline-block"></path><path class="path"d="M899.3 300c-20.9-32.7-46.5-61.1-75.9-84.2l-0.1-0.1c-1.3-1.1-2.2-1.8-2.9-2.4-4.5-2.8-9.6-4.3-15.1-4.3-10.3 0-21.6 5.3-31.1 14.5l-0.1 0.1c-8.4 13.5-3.9 35.9 9 45.2l0.1 0.1c6.1 2.5 14.7 9.7 20.8 15.4 9.4 8.7 23.6 23.7 38.1 45.6 24.3 36.8 53.3 99.7 53.3 190.8 0 91-27.4 153.9-50.3 190.6-13.7 22-27.2 36.9-36.1 45.6-8.6 8.3-15.3 13.5-20.1 15.5l-0.1 0.1c-13.9 9.8-17.2 28.6-8.1 46.7 3.8 7.7 17.2 12.9 27.3 12.9 3.8 0 13.9 0 17.4-3.5 0.7-0.7 1.5-1.4 3.3-2.8 28.1-22.9 52.6-51 72.7-83.8 38.8-63.2 58.5-137.6 58.5-221.4 0-83.4-20.4-157.6-60.6-220.6z"id="volume_2_icon"style="display:none"></path><path class="path"d="m670.797714 328.2c10.532571 0 20.918857 3.876571 28.891429 11.776l119.149714 117.467429 119.222857-117.394286a40.96 40.96 0 0 1 57.782857 0 39.789714 39.789714 0 0 1-0.146285 56.978286l-119.003429 117.394285 119.003429 117.394286a39.789714 39.789714 0 0 1 0 56.905143 41.106286 41.106286 0 0 1-57.709715 0l-119.149714-117.321143-119.222857 117.248a41.106286 41.106286 0 0 1-57.636572 0 39.789714 39.789714 0 0 1 0-56.978286l119.003429-117.321142-119.003429-117.394286a39.789714 39.789714 0 0 1 0-56.978286 40.813714 40.813714 0 0 1 28.818286-11.776z"id="volume_mute_icon"style="display: none"></path></svg></div></div>
</div>
</body>
<!-- 引入js文件 -->
<script type="text/javascript" src="./code.js"></script>
</html>

js代码

let duration = 0;
let percentage = null;
let currentVolume = 0;
let muted = false;
let timer = {startPlay: null, playing: null, warp: null, peachBlossom: null};
onload = function () {Window.myAudio = document.getElementById("myAudio");myAudio.volume = 0.5;currentVolume = myAudio.volume;setVolume(currentVolume);
}
let currentTime = document.getElementById("currentTime");
let progress = document.getElementById("progress");
//  音频播放结束后触发的事件
myAudio.addEventListener('ended', function () {clearInterval(timer.playing);clearInterval(timer.peachBlossom);peachBlossom.disappear();img.classList.remove("animation");btn.style.opacity = "1";btn2.classList.remove("btn_change");currentTime.innerText = "00:00";progress.style.width = "0";lrc.style.transform = "translateY(0px)";del_backgroundImage(lyric.length - 1);
})
myAudio.addEventListener("timeupdate", function () {//监听音频播放的实时时间事件let timeDisplay = Math.round(myAudio.currentTime * 100) / 100;//  判断是否正在修改播放进度(正在修改进度时,不改变进度条样式)if (!changeProgress) {progress.style.width = Math.round(timeDisplay / percentage * 100) / 100 + "%";}//用秒数来显示当前播放进度timeDisplay = Math.floor(timeDisplay);//分钟let minutes = parseInt(timeDisplay / 60);if (minutes < 10) {minutes = "0" + minutes;}//秒let seconds = Math.round(timeDisplay % 60);if (seconds < 10) {seconds = "0" + seconds;}currentTime.innerText = minutes + ":" + seconds;
})
class PeachBlossom {constructor(width,height,petalNumber) {this.peachBlossom = new Image();this.peachBlossom.src = "./images/peachBlossom.png";let canvas = document.getElementById("canvas");canvas.width = width;canvas.height = height;this.ctx = canvas.getContext("2d");this.width = width;this.height = height;this.petalNumber = petalNumber;let that = this;this.peachBlossom.onload = function () {that.drawWidth = that.peachBlossom.width / 10; //  50that.drawHeight = that.peachBlossom.height / 10;   //  50that.initialize();}}//  更新canvasupdate(){//  清空画布this.ctx.clearRect(0,0,this.width,this.height);// for循环更新所有花瓣坐标for (let i = 0; i < 100; i++) {this.petal[i].showX += this.petal[i].angle;this.petal[i].showY +=  this.petal[i].speed;//  判断当前花瓣是否超出屏幕高度,如果超出屏幕高度再重新随机选择一个花瓣,显示位置也随机if(this.petal[i].showY > this.height+this.drawHeight){let index = Math.floor(Math.random()*(this.petalNumber-1)+1);this.petal[i].drawX = (index % 10) * this.drawWidth;this.petal[i].drawY = Math.floor(index / 10) * this.drawHeight;this.petal[i].showX = Math.floor(Math.random()*(this.width-1)+1);this.petal[i].showY = -(Math.random() * this.height);this.petal[i].speed = (Math.random()*(13-7+1)+7) / 10;this.petal[i].angle = Math.random();if(Math.round(Math.random()*10)%2){this.petal[i].angle = -this.petal[i].angle;}}//  渲染更新后的花瓣this.ctx.drawImage(this.peachBlossom,this.petal[i].drawX,this.petal[i].drawY,this.drawWidth,this.drawHeight,this.petal[i].showX,this.petal[i].showY,this.drawWidth,this.drawHeight)}}//  花瓣渐渐消失disappear(){let that = this;let transparency = 1;let interval = setInterval(function () {transparency -= 0.01;//  这里里的this指向的是Window,所以要把Class类的this指向赋值给thatthat.ctx.clearRect(0,0,that.width,that.height);that.ctx.globalAlpha = transparency;for (let i = 0; i < that.petal.length; i++) {that.petal[i].showX += that.petal[i].angle;that.petal[i].showY +=  that.petal[i].speed;that.ctx.drawImage(that.peachBlossom,that.petal[i].drawX,that.petal[i].drawY,that.drawWidth,that.drawHeight,that.petal[i].showX,that.petal[i].showY,that.drawWidth,that.drawHeight)}if (transparency < 0){//  已消失,重置canvas的数据that.ctx.clearRect(0,0,that.width,that.height);that.ctx.globalAlpha = 1;//  重置数据that.initialize();//  清除当前定时器clearInterval(interval);}},18)}initialize(){this.petal = [];for (let i = 0; i < 100; i++) {let obj = {};let index = Math.floor(Math.random()*(this.petalNumber-1)+1);//  剪切图片的X坐标obj.drawX = (index % 10) * this.drawWidth;//  剪切图片的Y坐标obj.drawY = Math.floor(index / 10) * this.drawHeight;//  显示在屏幕的X坐标obj.showX = Math.floor(Math.random()*(this.width-1)+1);//  显示在屏幕的Y坐标obj.showY = -(Math.random() * this.height);//  飘落速度obj.speed = (Math.random()*(13-7+1)+7) / 10;//  飘落倾斜角度obj.angle = Math.random();if (obj.angle > 0.5){obj.angle = Math.random();}if(Math.round(Math.random()*10)%2){obj.angle = -obj.angle}this.petal.push(obj)}}
}
//  初始化对象
let peachBlossom = new PeachBlossom(window.screen.width,window.screen.height,100);
//  获取id为img的元素
let img = document.getElementById("img");
let lrc = document.getElementById("lrc");
function playMusic() {if (duration <= 0) {//  设置音频总时长setDuration(myAudio.duration);}//  获取当前音频播放时间let currentTime = myAudio.currentTime;if (currentTime == myAudio.duration) {img.classList.add("animation");myAudio.currentTime = 0;document.getElementById("lrc").style.transform = "translateY(0px)";} else if (currentTime > 0) {currentTime = currentTime.toFixed(3);let arr = currentTime.split(".");currentTime = (Number(arr[0]) * 1000) + Number(arr[1]);}//  定时更新、渲染canvas的数据timer.peachBlossom = setInterval(function () {peachBlossom.update()},18)img.style.animationPlayState = "running";//  当前是播放状态,隐藏播放按钮btn.style.opacity = "0";//  给第二个播放按钮添加类名以修改样式btn2.classList.add("btn_change");if (currentTime < lyric[0][0][0]) {//  当前未开始渲染歌词document.getElementById("line_0").classList.add("currentLine");myAudio.play();let start = new Date().getTime()//  未需要渲染歌词,(定时器)等待需要渲染歌词再执行playing函数timer.startPlay = setTimeout(function () {playing(0, 0, 0)}, lyric[0][0][0] - currentTime)} else if (currentTime > lyric[lyric.length - 1][0][0]) {//  渲染最后一行歌词let lastLine = lyric.length - 1;let translate = -(lastLine * 40 - 80);document.getElementById("line_" + lastLine).classList.add("currentLine");for (let i = 0; i < lyric[lastLine].length; i++) {document.getElementById("word_" + lastLine + "_" + i).style.backgroundImage = "-webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(255,255,255,0) 100%), -webkit-linear-gradient(left, #f00 100%, #000 0%)";if (currentTime < lyric[lastLine][i][0] + lyric[lastLine][i][1]) {//  调整歌词,等待换行adjustLyricProgress(currentTime, lastLine, i, translate);break;} else if (i === lyric[lastLine].length - 1) {//      歌词全部渲染完毕(已唱完)document.getElementById("lrc").style.transform = "translateY(" + translate + "px)";myAudio.play();}}} else {let translate = 0;for (let i = 1; i <= lyric.length; i++) {if (currentTime < lyric[i][0][0]) {if (i > 2) {translate = -((i-3) * 40);}//  给当前行歌词添加类名以调整当前行歌词样式document.getElementById("line_" + (i - 1)).classList.add("currentLine");for (let j = 0; j < lyric[i - 1].length; j++) {document.getElementById("word_" + (i - 1) + "_" + j).style.backgroundImage = "-webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(255,255,255,0) 100%), -webkit-linear-gradient(left, #f00 100%, #000 0%)";//  判断当前是否是当前行歌词的最后一个字if (j === lyric[i - 1].length - 1) {//  判断当前行歌词最后一个字是否渲染完成if (currentTime < lyric[i - 1][j][0] + lyric[i - 1][j][1]) {//  当前行最后一字未完成,调整歌词adjustLyricProgress(currentTime, i - 1, j, translate);} else {//  当前行最后一字已完成myAudio.play();lrc.style.transform = "translateY(" + translate + "px)";timer.startPlay = setTimeout(function () {document.getElementById("line_" + (i - 1)).classList.remove("currentLine");del_backgroundImage(i - 1);document.getElementById("line_" + i).classList.add("currentLine");//  当前行已结束,调整歌词translate -= 40;lrc.style.transform = "translateY(" + translate + "px)";playing(i, 0, translate);}, lyric[i][0][0] - currentTime)}} else if (currentTime < lyric[i - 1][j + 1][0]) {adjustLyricProgress(currentTime, i - 1, j, translate);break;}}break;}}}
}
function pauseMusic() {//  暂停,清楚所有定时器clearInterval(timer.peachBlossom);clearInterval(timer.playing);clearTimeout(timer.startPlay);clearTimeout(timer.warp);//  显示播放按钮btn.style.opacity = "1";//  删除第二个播放按钮类名以修改样式btn2.classList.remove("btn_change");//  暂停动画img.style.animationPlayState = "paused";//  暂停音频myAudio.pause();
}
function playing(lineNumber, wordNumber, translate = 0) {clearInterval(timer.peachBlossom);//  获取当前字的元素let element = document.getElementById("word_" + lineNumber + "_" + wordNumber);//  定时器间隔时间let intervalTime = 18;//  当前字的时长let duration = lyric[lineNumber][wordNumber][1];//  当前字已播放时间let pastTime = 0;//  获取当前行的元素let currentLine = document.getElementById("line_" + lineNumber);//  开始时间let startTime = new Date().getTime();timer.playing = setInterval(function () {//  定时执行里面代码pastTime += intervalTime;//  设置样式element.style.backgroundImage = "-webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(255,255,255,0) 100%), -webkit-linear-gradient(left, #f00 " + ((pastTime / duration).toFixed(2) * 100) + "%, #000 0%)";//  判断当前字是否已渲染完成if (pastTime >= duration) {//  当前字已播放完成,下一字wordNumber++;//  判断当前行是否已播放完成if (wordNumber === lyric[lineNumber].length) {//  下一行lineNumber++;if (lineNumber === lyric.length) {//  最后一行播放完成,播放结束timer.peachBlossom = setInterval(function () {peachBlossom.update()},intervalTime)// clearInterval(timer.playing);//  播放结束return;} else {//  下一行//  计算换行的时间let warpIntervalTime = lyric[lineNumber][0][0] - (lyric[lineNumber - 1][wordNumber - 1][0] + lyric[lineNumber - 1][wordNumber - 1][1]);wordNumber = 0if (warpIntervalTime > 5) {clearInterval(timer.playing);timer.peachBlossom = setInterval(function () {peachBlossom.update()},intervalTime);timer.warp = setTimeout(() => {if (lineNumber > 2 && lineNumber < lyric.length - 2) {//  歌词元素继续向上移动translate -= 40;//  设置歌词向上移动lrc.style.transform = "translateY(" + translate + "px)";}//  清除当前行的class类名currentLine.classList.remove("currentLine");//  重新获取当前行currentLine = document.getElementById("line_" + lineNumber);//  给当前行设置class类名currentLine.classList.add("currentLine");//  继续渲染歌词clearInterval(timer.peachBlossom);playing(lineNumber, 0, translate);//  清除上一行已渲染的歌词样式del_backgroundImage(lineNumber - 1);}, warpIntervalTime)return;}//  继续下一行if (lineNumber > 2 && lineNumber < lyric.length - 2) {//  歌词元素继续向上移动translate -= 40;//  设置歌词向上移动lrc.style.transform = "translateY(" + translate + "px)";}//  清除当前行的class类名currentLine.classList.remove("currentLine");//  重新获取当前行currentLine = document.getElementById("line_" + lineNumber);//  给当前行设置class类名currentLine.classList.add("currentLine");//  清除上一行已渲染的歌词样式del_backgroundImage(lineNumber - 1);}}//  重新下一个字的元素element = document.getElementById("word_" + lineNumber + "_" + wordNumber);//  获取时间戳let endTime = new Date().getTime();//  上一个字执行结束时间减去上一个字开始执行时间,再减去上一个字的时长得出误差时间let errorTime = (endTime - startTime) - duration;//  将结束时间作为下一个字开始执行的时间startTime = endTime;//  重新计算当前字的时长(当前字时长减去定时器误差)duration = lyric[lineNumber][wordNumber][1] - errorTime;//  当前字已播放时间设为0pastTime = 0;}peachBlossom.update();}, intervalTime)
}
let progressBar = document.getElementById("progressBar");
let body = document.getElementsByTagName("body")[0];
let changeProgress = false;
//  监听元素鼠标按下事件
progressBar.onmousedown = function (event) {//  判断是否为鼠标左键       0为鼠标左键,1为鼠标中键,2为鼠标右键if (event.button === 0) {changeProgress = true;//  修改进度(样式)progress.style.width = ((Math.floor(((event.clientX - progressBar.getBoundingClientRect().left) / progressBar.getBoundingClientRect().width) * 10000) / 100)) + "%";//  监听鼠标移动事件body.onmousemove = function (event) {let progressPercentage = Math.floor(((event.clientX - progressBar.getBoundingClientRect().left) / progressBar.getBoundingClientRect().width) * 10000) / 100;if (progressPercentage < 0) {progressPercentage = 0;} else if (progressPercentage > 100) {progressPercentage = 100;}progress.style.width = progressPercentage + "%";}}
}
//  监听鼠标松开事件
body.onmouseup = function (event) {//  判断当前是否在拖动播放进度条if (changeProgress) {changeProgress = false;body.onmousemove = null;myAudio.currentTime = myAudio.duration / 100 * parseFloat(progress.style.width);let currentLine = document.getElementsByClassName("currentLine")[0];if (currentLine) {del_backgroundImage(currentLine.getAttribute("data-lineNumber"))currentLine.classList.remove("currentLine");}// 修改了播放进度,先暂停再播放pauseMusic();playMusic();}
}
//  根据id获取元素
let volume = document.getElementById("volume");
let currentVolumeElement = document.getElementById("currentVolume");
let currentVolumeText = document.getElementById("currentVolumeText");
let volumeBox = document.getElementById("volumeBox");
let volumeBar = document.getElementById("volumeBar");
//  监听volumeBar元素的鼠标按下事件
volumeBar.onmousedown = function (event) {currentVolume = Math.round((1 - ((event.clientY - volumeBar.getBoundingClientRect().top) / volumeBar.getBoundingClientRect().height)) * 100) / 100setVolume(currentVolume);if (muted) {//  更改静音状态muted = false;//  更改音频的静音状态myAudio.muted = false;}//  监听volumeBox元素的鼠标移动事件volumeBox.onmousemove = function (event) {currentVolume = Math.round(100 - (event.clientY - volumeBar.getBoundingClientRect().top)) / 100;if (currentVolume < 0) {currentVolume = 0;} else if (currentVolume > 1) {currentVolume = 1}setVolume(currentVolume);}
}
//  监听volume元素的鼠标松开事件
volume.onmouseup = function () {//  鼠标松开音量元素的区域,取消监听volumeBox元素的鼠标移动volumeBox.onmousemove = null;
}
//  监听volume元素的鼠标移出事件
volume.onmouseleave = function () {//  鼠标移出音量元素的区域,取消监听volumeBox元素的鼠标移动volumeBox.onmousemove = null;
}
//  监听volume元素的鼠标滚动事件
volume.onmousewheel = function (event) {//  参数deltaY为100时,鼠标滚轮向下滚动;参数deltaY为-100时,鼠标滚轮向上滚动if (event.deltaY > 0) {if (muted) {//  当前已是静音,不能减音量。return返回return;}currentVolume -= 0.05;} else {if (muted) {//  当前是静音,所以直接把音量加到5currentVolume = 0.05;//  更改静音状态muted = false;//  更改音频的静音状态myAudio.muted = muted;} else {//  当前非静音,所以在原音量的基础上加5currentVolume += 0.05;}}setVolume(currentVolume);
}
//  根据id获取元素
let volumeBtn = document.getElementById("volumeBtn");
let volume_1_icon = document.getElementById("volume_1_icon");
let volume_2_icon = document.getElementById("volume_2_icon");
let volume_mute_icon = document.getElementById("volume_mute_icon");
//  监听volumeBtn(音量按钮)元素的鼠标点击事件
volumeBtn.onclick = function (event) {muted = !muted;myAudio.muted = muted;if (muted) {//  设置为静音setVolume(0, false)} else {setVolume(myAudio.volume, false)}
}
//  设置音量
function setVolume(currentVolume, changeVolume = true) {if (currentVolume > 1) {currentVolume = 1;} else if (currentVolume <= 0) {currentVolume = 0;volume_1_icon.style.display = "none";volume_2_icon.style.display = "none";volume_mute_icon.style.display = "inline-block";} else {currentVolume = Math.round(currentVolume * 100) / 100;}if (currentVolume > 0.33) {volume_1_icon.style.display = "inline-block";volume_2_icon.style.display = "inline-block";volume_mute_icon.style.display = "none";} else if (currentVolume > 0) {volume_1_icon.style.display = "inline-block";volume_2_icon.style.display = "none";volume_mute_icon.style.display = "none";}if (changeVolume) {myAudio.volume = currentVolume;}currentVolumeElement.style.height = (currentVolume * 100) + "px";currentVolumeText.innerText = parseInt(currentVolume * 100);
}
let lyric = getLrc();
let btn = document.getElementById("btn");
let btn2 = document.getElementById("btn2");
//  监听播放、播放的按钮的点击事件
function play_pause() {//  根据音频的播放状态执行对应函数if (myAudio.paused) {playMusic();} else {pauseMusic();}
}
//  设置进度条的时间
function setDuration(time) {duration = time;percentage = Math.round(duration) / 100;let minutes = "00:";if (duration >= 60) {minutes = parseInt(duration / 60);if (minutes < 10) {minutes = "0" + minutes + ":"}}let seconds = parseInt(duration % 60);if (seconds < 10) {seconds = "0" + seconds}document.getElementById("duration").innerText = minutes + seconds;
}
//  调整歌词进度
function adjustLyricProgress(currentTime, lineNumber, wordNumber, translate) {lrc.style.transform = "translateY(" + translate + "px)";let pastTime = currentTime - lyric[lineNumber][wordNumber][0];//  获取当前字的元素let element = document.getElementById("word_" + lineNumber + "_" + wordNumber);//  定时器间隔时间let intervalTime = 18;//  当前字的时长let duration = lyric[lineNumber][wordNumber][1];if (duration % intervalTime > intervalTime / 2) {duration += duration % intervalTime;} else {duration -= duration % intervalTime;}element.style.backgroundImage = "-webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(255,255,255,0) 100%), -webkit-linear-gradient(left, #f00 " + ((pastTime / duration).toFixed(2) * 100) + "%, #000 0%)";myAudio.play();timer.playing = setInterval(function () {pastTime += intervalTime;element.style.backgroundImage = "-webkit-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(255,255,255,0) 100%), -webkit-linear-gradient(left, #f00 " + ((pastTime / duration).toFixed(2) * 100) + "%, #000 0%)";if (pastTime >= duration) {//  当前字结束clearInterval(timer.playing);if (wordNumber < lyric[lineNumber].length - 1) {playing(lineNumber, wordNumber + 1, translate);} else if (lineNumber < lyric.length - 1) {//  判断是否最后一行,如果不是最后一行则继续执行translate -= 40;lrc.style.transform = "translateY(" + translate + "px)";timer.startPlay = setTimeout(function () {document.getElementById("line_" + lineNumber).classList.remove("currentLine");del_backgroundImage(lineNumber);document.getElementById("line_" + (lineNumber + 1)).classList.add("currentLine");playing(lineNumber + 1, 0, translate);}, lyric[lineNumber + 1][0][0] - (lyric[lineNumber][wordNumber][0] + lyric[lineNumber][wordNumber][1]))}}}, intervalTime)
}
//  清楚上一行渲染的歌词样式
function del_backgroundImage(lineNumber) {for (let i = 0; i < lyric[lineNumber].length; i++) {document.getElementById("word_" + lineNumber + "_" + i).style.backgroundImage = "-webkit-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 100%), -webkit-linear-gradient(left, #000 0%, #000 0%)";}
}
//  从txt文件获取歌词数据
function getLrc() {let txt = "";let ajax = new XMLHttpRequest();ajax.open("GET", "./music/music.txt", false);ajax.onreadystatechange = function () {txt = ajax.responseText;};ajax.send(null);//  将字符串以回车符(\n)分割成每一行文本为一个数组元素let arr = txt.split("\n");//  歌词内容let lyric = [];let lrcElement = document.getElementById("lrc")//  有些不是歌词,所以lineNumber从0开始,判断是歌词行,再加1。这样动态添加的元素的id和class类名序号能跟数组索引对上let lineNumber = 0;for (let i = 0; i < arr.length; i++) {//  删除每行文本全部的\r符号arr[i] = arr[i].replace(/[\r]/g, "");//  如果当前行文本存在"<"和">"符号,说明该行文本是歌词if (arr[i].indexOf("<") > -1 && arr[i].indexOf(">") > -1) {lrcElement.innerHTML += "<p id=line_" + lineNumber + " data-lineNumber=" + lineNumber + "></p>";//  每行歌词是一个一维数组元素,每个字是一个二维数组(包含"开始时间","时长","文字")//  每一行的开始时间(转为数值类型)let startTime = Number(arr[i].slice(1, arr[i].indexOf(",")));//  截取改行文本从"]"符号开始,一直到最后的文本arr[i] = arr[i].slice(arr[i].indexOf("]") + 1);//  每一行的数据let line = [];let nextTime = 0;let lineElement = document.getElementById("line_" + lineNumber)while (arr[i]) {let str = arr[i].slice(0, arr[i].indexOf(">") + 1);let time = Number(str.slice(str.indexOf(",") + 1, str.lastIndexOf(",")));nextTime += time;arr[i] = arr[i].slice(str.length);let word = "";let index = arr[i].indexOf(String(nextTime));if (index > -1) {word = arr[i].slice(0, index - 1);} else {word = arr[i];}lineElement.innerHTML += "<span id=word_" + lineNumber + "_" + line.length + " class=word_" + lineNumber + "_" + line.length + ">" + word + "</span>";arr[i] = arr[i].slice(word.length);line.push([startTime, time, word]);startTime += time;}lyric.push(line);lineNumber++;} else if (arr[i].indexOf("total:") > -1) {let total = arr[i].slice(7, arr[i].indexOf("]"))if (total) {setDuration(total / 1000);}} else if (arr[i].indexOf("ti:") > -1) {//  歌名let songName = arr[i].slice(4, arr[i].indexOf("]"));document.getElementById('songName').innerText = "歌名:" + songName;} else if (arr[i].indexOf("ar:") > -1) {//  歌手let singerName = arr[i].slice(4, arr[i].indexOf("]"));document.getElementById('singerName').innerText = "歌手:" + singerName;}}return lyric;
}

css代码

body {user-select: none;overflow: hidden;
}
#canvas {position: absolute;
}
audio {display: none;
}
.music {margin: 20px auto 0;text-align: center;font-family: "楷体", "楷体_GB2312";cursor: default;
}
.music .songInfo p {display: inline-block;margin: 0 50px;
}
.player {position: relative;margin: 50px auto;width: 200px;height: 200px;background-color: #333;border-radius: 50%;text-align: center;
}
.player img {margin: 30px;width: 140px;height: 140px;border-radius: 50%;
}
.player .animation {animation: rotate 8s linear infinite;animation-play-state: paused;
}
@keyframes rotate {0% {transform: rotate(0deg);}100% {transform: rotate(360deg)}
}
.btn {display: inline-block;width: 40px;height: 40px;background-color: rgba(0, 0, 0, 0.2);border: 1px solid #fff;border-radius: 50%;margin: -20px;position: absolute;top: 50%;left: 50%;
}
.btn:after {content: "";display: inline-block;border: 12px solid transparent;border-left-color: #fff;border-radius: 15%;position: absolute;top: 8px;left: 16px;
}
.music .songInfo {font-size: 28px;
}
.music .lrc_box {height: 362px;overflow: hidden;
}
.lrc_box .lrc {/* 歌词向上移动的过渡动画 */transition: transform 200ms;
}
.lrc_box .lrc .blank {height: 80px;
}
.lrc_box .lrc p {line-height: 40px;font-size: 26px;padding: 0;margin: 0;/* 文字放大和缩小的过渡动画 */transition: font-size 500ms;position: relative;
}
.lrc_box .lrc p > span {-webkit-background-clip: text;-webkit-text-fill-color: transparent;background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 100%), -webkit-linear-gradient(left, #000 0%, #000 0%);
}
.lrc_box .lrc .currentLine {font-size: 30px;
}
.control {width: 102%;height: 50px;background-image: linear-gradient(#f0f0f0, #5c8bfc, #005cec, #051959);position: fixed;left: -2%;bottom: 2px;display: flex;justify-content: space-evenly;cursor: default;padding: 20px;
}
.control>p{position: relative;top: -10px;
}
.control .btn {width: 30px;height: 30px;left: 20px;top: 24px;
}
.control .btn:after {border: 10px solid transparent;border-left-color: #fff;border-radius: 15%;top: 5px;left: 12px;
}
.control .btn:before {content: "";width: 14px;height: 14px;border-style: double;border-width: 0 0 0 12px;border-color: #fff;position: absolute;top: 8px;left: 9px;display: none;
}
.control .btn_change:after {display: none;
}
.control .btn_change:before {display: inline-block;
}
.control .time_progressBar {width: 50%;display: flex;align-items: center;
}
.control .time {display: flex;margin-right: 8px;
}
.control .time p {margin-right: 3px;
}
.control .progressBar {background-color: #fff;width: 100%;height: 6px;border-radius: 30px;cursor: pointer;
}
.control .progressBar .progress {background-color: #0010ce;width: 0;height: 6px;border-radius: 30px;position: relative;margin: 0;
}
.control .progressBar .progress:after {content: "";width: 12px;height: 12px;border-radius: 50%;background-color: #fff;position: absolute;right: -8px;top: 50%;margin: -6px 0;
}
.progressBar:hover .progress:after {opacity: 1 !important;
}
.progressBar:active .progress:after {opacity: 1 !important;
}
.volume {width: 66px;position: relative;top: 12px;cursor: pointer;text-align: center;
}
.path {fill: #fff;
}
.volume:hover .path {fill: #00f;
}
.volume:hover .volumeBox {display: flex;
}
.volumeBox {width: 66px;background-color: #f0f0f0;position: absolute;bottom: 66px;left: 0;border-radius: 6px;/* 改这里为display:none隐藏 */display: none;flex-direction: column;align-items: center;padding: 22px 0;
}
.volumeBox:after {z-index: 9999;content: "";display: block;width: 0;height: 0;border: 12px solid transparent;border-top-color: #f0f0f0;position: absolute;left: 17px;bottom: -24px;
}
.volumeBar {width: 4px;height: 100px;border-radius: 30px;margin: 0;background-color: #ccc;cursor: pointer;transform: rotateZ(180deg);
}
.currentVolume {background-color: #2182e8;width: 4px;height: 0%;border-radius: 30px;position: relative;margin: 0;
}
.currentVolume:after {content: "";width: 8px;height: 8px;border-radius: 50%;background-color: #2182e8;position: absolute;bottom: 0;left: 50%;margin-left: -4px;
}
.volumeText {margin: 10px 0 0 0;color: #999;
}

注意:由于浏览器默认是不允许本地“跨域”请求,所以直接打开html文件,无法加载txt歌词文件,所以需要用到IDE编辑器打开(大部分IDE会默认创建本地服务器)或者通过网络请求加载txt文件!

js歌词逐字滚动效果相关推荐

  1. js实现抽奖滚动效果

    目录 一.效果展示 二.代码说话 三.总结经验 一.效果展示 本文介绍js实现抽奖滚动效果的实现过程.具体效果如下图: 二.代码说话 话不多说,上代码最实在. 1.scroll.js var Scro ...

  2. android开发歌词滑动效果_android实现歌词自动滚动效果

    最近在做Android 的MP3播放的项目,要实现歌词的自动滚动,以及同步显示. lyric的歌词解析主要用yoyoplayer里面的,显示部分参考了这里 ,这里只是模拟MP3歌词的滚动. 先上一下效 ...

  3. JS 实现消息滚动效果

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. js实现title滚动效果

    js实现title滚动效果 原理:取第一个字符,放到尾部,定时循环操作,在视觉就有滚动效果了.直接上代码了 方式一 var titleText = "您有新订单,请及时处理!".s ...

  5. js解析lrc 实现lrc歌词同步滚动效果

    这两天想着做一个h5的网页播放器,实现歌词同步滚动 但是上网找了很多资料,竟发现没有比较完善的代码供参考,但是无意间看到了百度的千千音乐有这样的效果,就想着一定能通过js实现 经过两三天的努力,终于做 ...

  6. android开发歌词滑动效果_Android 歌词同步滚动效果

    歌词是播放器类App必不可少的组件,而一般的歌词组件都需要做到歌词的显示与播放进度同步.我们知道,歌词是如下所示的文件: lrc [ti:原来爱情这么伤] [ar:梁咏琪] [al:给自己的情歌] [ ...

  7. html完成公告滚动条,原生js实现公告滚动效果

    本文实例为大家分享了js实现公告滚动展示的具体代码,供大家参考,具体内容如下 1.html结构 我是公告1 我是公告2 我是公告3 我是公告4 2.css样式 body, div, ul, li { ...

  8. 用JS解析LRC格式的歌词,实现歌词同步滚动效果

    用JS解析LRC格式的歌词 1.把歌词载入. 方法一:直接把歌词粘贴到一个textarea文本域中,然后把它设置为隐藏. <!-- LRC歌词 --> <textarea id=&q ...

  9. js实现文字滚动效果

    在之前小编已经和大家介绍了一些常用的js动画效果,在此,和大家介绍一种可能不太常用的动画效果.该动画效果与文字相关,且,虽然不常用,但几乎每个人都见过它.相信大家都使用酷狗音乐或是网易云音乐进行音乐的 ...

最新文章

  1. python 相交链表
  2. 洛谷P3616 富金森林公园
  3. linux运行脚本报错:/bin/bash^M: bad interpreter: No such file or directory(dos2unix )(/bin/sh^M)(回车符、换行符)
  4. SQL Server中删除重复数据的2个方法
  5. WPF 透明窗口在桌面上放虫子。。。
  6. 如何在Global.asax中判断是否是ajax请求
  7. PHP即将退出,PHP4即将退出历史舞台
  8. 江苏小高考计算机操作题软件,江苏小高考现神题:求微信启动画面的拍摄时间...
  9. 连微信红包都在催我们长大:90后首次成为红包主力军
  10. 开源协议栈 rlc rrc_LTE的组网架构与接口协议
  11. There is no more space for virtual disk .vmdk.
  12. EncodingAESKey
  13. 如何学好一门开发技术
  14. 怎么实现多用户同时远程连接到一台电脑上
  15. (Note)同比和环比
  16. Latex文档中 插入符号和编号
  17. 证件照换底色,快速简单!(附去水印宝藏工具)
  18. java设计模式总结1
  19. 区块链关键技术1(笔记)
  20. Mac Chrome 访问证书有问题的https网站时无法忽略风险继续浏览

热门文章

  1. Android 官方模拟器7.0+ ROOT操作(以把CA证书刷到系统信任证书为例)
  2. TiDB:Raft与Multi Raft
  3. 中兴高管调整:为什么是殷一民?
  4. Python入门习题大全——汽车
  5. unet脑肿瘤分割_3D脑肿瘤分割的Dice损失函数的优化
  6. R语言绘制Donut chart
  7. 一款免费轻量级web报表工具
  8. STM32CubeMX系列10——TFT-LCD的使用(FSMC接口、8080通信协议)
  9. 人工智能初创公司创办过程中的三个关键教训
  10. 二进制原码、反码、补码及符号位进位