ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

js歌词逐字滚动效果

2021-11-17 20:01:17  阅读:522  来源: 互联网

标签:style 逐字 歌词 js getElementById let lineNumber lyric document


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; //  50
            that.drawHeight = that.peachBlossom.height / 10;   //  50
            that.initialize();
        }
    }
    //  更新canvas
    update(){
        //  清空画布
        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指向赋值给that
            that.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 = 0
                    if (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;
            //  当前字已播放时间设为0
            pastTime = 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) / 100
    setVolume(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) {
            //  当前是静音,所以直接把音量加到5
            currentVolume = 0.05;
            //  更改静音状态
            muted = false;
            //  更改音频的静音状态
            myAudio.muted = muted;
        } else {
            //  当前非静音,所以在原音量的基础上加5
            currentVolume += 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文件!

标签:style,逐字,歌词,js,getElementById,let,lineNumber,lyric,document
来源: https://blog.csdn.net/qq_38432429/article/details/121374475

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有