JS之歌词滚动案例

让我为大家带来一个歌词滚动的案例吧!
详细的介绍都在代码块中
我很希望大家可以自己动手尝试一下,如果需要晴天的mp3音频文件可以私信我
上代码:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>歌词滚动title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        ul {
            list-style: none;
            transition: all 0.5s;
        }
        body {
            background-color: #000;
        }
        audio {
            display: block;
            margin: 50px auto;
            width: 400px;
        }
        .container {
            text-align: center;
            color: #fff;
            height: 400px;
            overflow: hidden;
        }
        ul li {
            height: 40px;
            line-height: 40px;
            transition: all 0.5s;
        }
        /* 对应的歌词设置active */
        .active {
            color: red;
            /* 建议使用transform font-size会造成reflow重新布局 效率变低 */
            /* transform不在渲染主线程上执行 而是在合成线程上执行 就不会造成reflow */
            transform: scale(1.5);
        }
    style>
head>
<body>
    
    <audio src="周杰伦-晴天.mp3" controls>audio>
    
    <div class="container">
        
        <ul>
        ul>
    div>
body>
<script>
    // 歌词
    let lrc = `[00:00.71]晴天 - 周杰伦
[00:28.84]故事的小黄花
[00:32.34]从出生那年就飘着
[00:35.85]童年的荡秋千
[00:39.41]随记忆一直晃到现在
[00:42.77]rui sou sou xi dou xi la
[00:45.50]sou la xi xi xi xi la xi la sou
[00:49.41]吹着前奏望着天空
[00:52.60]我想起花瓣试着掉落
[00:56.10]为你翘课的那一天
[00:58.29]花落的那一天
[01:00.14]教室的那一间
[01:01.79]我怎么看不见
[01:03.61]消失的下雨天
[01:05.38]我好想再淋一遍
[01:09.51]没想到失去的勇气我还留着
[01:15.72]好想再问一遍
[01:17.47]你会等待还是离开
[01:24.46]刮风这天我试过握着你手
[01:30.18]但偏偏雨渐渐大到我看你不见
[01:38.50]还要多久我才能在你身边
[01:44.93]等到放晴的那天也许我会比较好一点
[01:52.41]从前从前有个人爱你很久
[01:58.07]但偏偏风渐渐把距离吹得好远
[02:06.44]好不容易又能再多爱一天
[02:12.81]但故事的最后你好像还是说了拜拜
[02:33.93]为你翘课的那一天
[02:36.39]花落的那一天
[02:38.13]教室的那一间
[02:39.84]我怎么看不见
[02:41.55]消失的下雨天
[02:43.31]我好想再淋一遍
[02:47.39]没想到失去的勇气我还留着
[02:53.39]好想再问一遍
[02:55.49]你会等待还是离开
[03:02.46]刮风这天我试过握着你手
[03:08.12]但偏偏雨渐渐大到我看你不见
[03:16.54]还要多久我才能在你身边
[03:23.10]等到放晴的那天也许我会比较好一点
[03:30.49]从前从前有个人爱你很久
[03:36.26]但偏偏风渐渐把距离吹得好远
[03:44.48]好不容易又能再多爱一天
[03:51.05]但故事的最后你好像还是说了拜拜
[03:57.65]刮风这天我试过握着你手
[04:01.45]但偏偏雨渐渐大到我看你不见
[04:04.98]还要多久我才能够在你身边
[04:08.64]等到放晴那天也许我会比较好一点
[04:12.34]从前从前有个人爱你很久
[04:15.40]但偏偏雨渐渐把距离吹得好远
[04:19.05]好不容易又能再多爱一天
[04:22.42]但故事的最后你好像还是说了吧`
    // 获取audio
    const audio = document.querySelector("audio")
    // 获取容器
    const container = document.querySelector(".container")
    // 获取ul
    const ul = document.querySelector("ul")
    // 第一步渲染页面,我们需要用到split \n换行切割 记住是\n 不是/n
    const lrcArr = lrc.split("\n")
    // console.log(lrcArr);
    // 准备好一个数组接收
    const resultArr = []
    // 因为我们是[00:00:00]这样的形式我们需要继续切割
    for (let i = 0; i < lrcArr.length; i++) {
        const lrcData = lrcArr[i].split("]")
        // 我们取到lrcData[0]与lrcData[1]
        // 获取到 00:00:00这样的字符串
        const times = lrcData[0].slice(1)
        // 声明一个对象 我们把时间与歌词依次存入
        const objLrc = {
            // 时间 不过我们需要处理一下时间 把00:00:00这样的格式转换为秒
            seconds: parseTime(times),
            // 歌词
            lrc: lrcData[1]
        }
        // 添加到resultArr中
        resultArr.push(objLrc)
    }
    // 处理时间转换为秒
    function parseTime(times) {
        // 切割times 用:切割
        let timesArr = times.split(":")
        // console.log(timesArr);
        // 把下标为0的分钟转换为秒 但要注意 当前时间为字符串型 我们需要转换为数字型
        // 介绍一下+ 这个是数值中的隐式转换
        return +timesArr[0] * 60 + +timesArr[1]
    }
    // 渲染页面
    function createLis() {
        for (let i = 0; i < resultArr.length; i++) {
            let li = document.createElement("li")
            li.innerHTML = resultArr[i].lrc
            ul.appendChild(li)
        }
    }
    createLis()
    // 获取到下标
    function getIndex() {
        // 获取音频的当前时间
        let current = audio.currentTime
        for (let i = 0; i < resultArr.length; i++) {
            // 判断 如果当前时间小于seconds 下标为 i - 1
            if (current < resultArr[i].seconds) {
                return i - 1
            }
        }
        // 找遍了没有找到 说明播放到最后一句了
        return resultArr.length - 1
    }
    // 获取到container的高度
    const containerHeight = container.clientHeight
    // 获取到第一个li的高度
    const liHeight = ul.children[0].clientHeight
    // 设置最大最小偏移 解决效果不佳
    const minOffset = 0
    const maxOffset = ul.clientHeight - containerHeight
    // 滚动效果
    function setOffset() {
        // 下标
        let index = getIndex()
        // 滚动到哪了 li的高度乘以下标就是对应的歌词 
        // 然后减去容器的一半 这时对应的li就在接近中间的位置
        // 我们再加上li一半的高度这时对应li就在中间
        let offset = liHeight * index - containerHeight / 2 + liHeight / 2
        // 判断
        // 为什么offset会小于0?
        // 假设现在下标为0 选取到了第0个
        // 那么就是 liHeight*0 - 200+liHeight/2
        if (offset < minOffset) {
            // offset赋为minOffset
            offset = minOffset
        }
        // 为什么会大于maxOffset?
        // 当我们歌到了最后的时候 就会造成这种情况
        if (offset > maxOffset) {
            // offset赋为maxOffset
            offset = maxOffset
        }
        // 现在可以滚动了 滚动ul
        // 建议大家使用transform
        // 好处在哪? 如果使用margin 会造成reflow重新布局 效率会出现问题
        // transform不在渲染主线程上执行 而是在合成线程上执行 就不会造成reflow
        ul.style.transform = `translateY(-${offset}px)`
        // 设置active
        // 首先我们获取到active
        let li = ul.querySelector(".active")
        // 存在就移除
        if (li) {
            li.classList.remove("active");
        }
        // 获取到下标对应的歌词
        li = ul.children[index];
        if (li) {
            li.classList.add("active");
        }
    }
    // 我们需要用到audio中的timeupdate事件
    audio.addEventListener("timeupdate", setOffset)
script>
html>

感谢大家的阅读,如有不对的地方,可以向我提出,感谢大家!

你可能感兴趣的:(css,前端,javascript)