js歌词逐字滚动效果
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歌词逐字滚动效果相关推荐
- js实现抽奖滚动效果
目录 一.效果展示 二.代码说话 三.总结经验 一.效果展示 本文介绍js实现抽奖滚动效果的实现过程.具体效果如下图: 二.代码说话 话不多说,上代码最实在. 1.scroll.js var Scro ...
- android开发歌词滑动效果_android实现歌词自动滚动效果
最近在做Android 的MP3播放的项目,要实现歌词的自动滚动,以及同步显示. lyric的歌词解析主要用yoyoplayer里面的,显示部分参考了这里 ,这里只是模拟MP3歌词的滚动. 先上一下效 ...
- JS 实现消息滚动效果
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- js实现title滚动效果
js实现title滚动效果 原理:取第一个字符,放到尾部,定时循环操作,在视觉就有滚动效果了.直接上代码了 方式一 var titleText = "您有新订单,请及时处理!".s ...
- js解析lrc 实现lrc歌词同步滚动效果
这两天想着做一个h5的网页播放器,实现歌词同步滚动 但是上网找了很多资料,竟发现没有比较完善的代码供参考,但是无意间看到了百度的千千音乐有这样的效果,就想着一定能通过js实现 经过两三天的努力,终于做 ...
- android开发歌词滑动效果_Android 歌词同步滚动效果
歌词是播放器类App必不可少的组件,而一般的歌词组件都需要做到歌词的显示与播放进度同步.我们知道,歌词是如下所示的文件: lrc [ti:原来爱情这么伤] [ar:梁咏琪] [al:给自己的情歌] [ ...
- html完成公告滚动条,原生js实现公告滚动效果
本文实例为大家分享了js实现公告滚动展示的具体代码,供大家参考,具体内容如下 1.html结构 我是公告1 我是公告2 我是公告3 我是公告4 2.css样式 body, div, ul, li { ...
- 用JS解析LRC格式的歌词,实现歌词同步滚动效果
用JS解析LRC格式的歌词 1.把歌词载入. 方法一:直接把歌词粘贴到一个textarea文本域中,然后把它设置为隐藏. <!-- LRC歌词 --> <textarea id=&q ...
- js实现文字滚动效果
在之前小编已经和大家介绍了一些常用的js动画效果,在此,和大家介绍一种可能不太常用的动画效果.该动画效果与文字相关,且,虽然不常用,但几乎每个人都见过它.相信大家都使用酷狗音乐或是网易云音乐进行音乐的 ...
最新文章
- python 相交链表
- 洛谷P3616 富金森林公园
- linux运行脚本报错:/bin/bash^M: bad interpreter: No such file or directory(dos2unix )(/bin/sh^M)(回车符、换行符)
- SQL Server中删除重复数据的2个方法
- WPF 透明窗口在桌面上放虫子。。。
- 如何在Global.asax中判断是否是ajax请求
- PHP即将退出,PHP4即将退出历史舞台
- 江苏小高考计算机操作题软件,江苏小高考现神题:求微信启动画面的拍摄时间...
- 连微信红包都在催我们长大:90后首次成为红包主力军
- 开源协议栈 rlc rrc_LTE的组网架构与接口协议
- There is no more space for virtual disk .vmdk.
- EncodingAESKey
- 如何学好一门开发技术
- 怎么实现多用户同时远程连接到一台电脑上
- (Note)同比和环比
- Latex文档中 插入符号和编号
- 证件照换底色,快速简单!(附去水印宝藏工具)
- java设计模式总结1
- 区块链关键技术1(笔记)
- Mac Chrome 访问证书有问题的https网站时无法忽略风险继续浏览