前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学会歌词滚动实现,让你的音乐页面更炫酷!

学会歌词滚动实现,让你的音乐页面更炫酷!

作者头像
友儿
发布2024-08-20 11:09:35
1450
发布2024-08-20 11:09:35
举报
文章被收录于专栏:友儿

实现效果

歌词滚动.gif
歌词滚动.gif

实现分析

解析歌词字符串转化为对象

代码语言:javascript
复制
var lyrics = `[00:00.000]漂洋过海来看你-孙露
[00:09.480]词:李宗盛
[00:18.960]曲:李宗盛
[00:28.440]为你我用了半年的积蓄
[00:31.980]漂洋过海的来看你
......`;

function parseLyrics() {
    let Things = lyrics.split('\n');
    let result = [];
    for (var i = 0; i < Things.length; i++) {
        let str = Things[i].split(']');
        let timeStr = str[0].substring(1);
        let timeArr = timeStr.split(':');
        let time = +timeArr[0] * 60 + +timeArr[1];
        let obj = {
            time: time,
            words: str[1],
        };
        result.push(obj);
    }
    return result;
}
  • parseLyrics 函数通过对输入的歌词字符串进行分割和处理,将时间部分转换为以秒为单位的数值,并与对应的歌词文本组合成对象,存储在 result 数组中。这样的对象形式方便后续根据时间进行查找和操作。

根据歌词对象和播放器当前播放时间计算当前播放到的歌词

代码语言:javascript
复制

function subscript() {
    let curTime = doms.audio.currentTime;
    for (var i = 0; i < lyricsData.length; i++) {
        if (curTime < lyricsData[i].time) {
            return i - 1;
        }
    }
    return lyricsData.length - 1;
}
  • subscript 函数接受当前音频的播放时间 curTime ,通过遍历歌词对象数组,比较时间来确定当前播放到的歌词索引。

把解析的歌词内容呈现到页面

代码语言:javascript
复制
function initLyricsHtml() {
    let frag = document.createDocumentFragment();
    for (var i = 0; i < lyricsData.length; i++) {
        let li = document.createElement('li');
        li.textContent = lyricsData[i].words;
        frag.appendChild(li);
    }
    doms.ul.appendChild(frag);
}
  • initLyricsHtml 函数创建 li 元素并填充歌词文本,使用 DocumentFragment 来优化性能。DocumentFragment 是一个轻量级的文档片段,它可以容纳多个 DOM 节点,当将其添加到文档中时,只会发生一次页面重绘或回流,从而提高性能。最后将所有 li 元素添加到 ul 中展示歌词。

根据当前播放到的歌词计算出 ul 向上偏移的位置以及当前高亮歌词

QQ截图20240819143328.png
QQ截图20240819143328.png
2种边界情况.png
2种边界情况.png
代码语言:javascript
复制
function setOffset() {
    let index = subscript();
    let offset = liHeight * index + liHeight / 2 - containerHeight / 2;
    if (offset < 0) {
        offset = 0;
    }
    if (offset > maxOffset) {
        offset = maxOffset;
    }
    doms.ul.style.transform = `translateY(-${offset}px)`;

    let liActive = doms.ul.querySelector('.active');
    if (liActive) {
        liActive.classList.remove('active');
    }
    let li = doms.ul.children[index];
    if (li) {
        li.classList.add('active');
    }
}
  • 首先计算了一些与页面布局相关的高度值,如容器高度、每行歌词高度和最大偏移量。
  • setOffset 函数根据当前播放的歌词索引计算 ul 的偏移量,确保当前歌词在容器中显示合适,并设置当前高亮的歌词行。使用 translateY 而不是 top 主要是因为 translateY 是通过 CSS 变换来实现元素的位移,它在性能上通常比直接修改 top 属性更优。translateY 可以利用硬件加速,并且不会引起页面的重布局,从而使页面的渲染更加流畅。

给播放器添加监听器监控 timeupdate 事件,执行 ul 偏移

代码语言:javascript
复制
doms.audio.addEventListener('timeupdate',setOffset);
  • doms.audio.addEventListener('timeupdate', setOffset); 这行代码使得在音频播放时间不断更新时,能够及时调用 setOffset 函数来调整歌词的显示位置和高亮状态。

完整的代码

index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>歌词滚动</title>
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
    <link rel="stylesheet" href="index.css" />
</head>
<body>
    <audio controls src="./孙露-漂洋过海来看你.mp3"></audio>
    <div class="container">
        <ul class="lrc-list"></ul>
    </div>
    <script src="data.js"></script>
    <script src="index.js"></script>
</body>
</html>

index.css

代码语言:javascript
复制
*{
    margin: 0;
    padding: 0;
}
body{
    background: #000;
    color: #666;
    text-align: center;
}
audio{
    width: 450px;
    margin: 30px 0;
}
.container{
    height: 420px;
    overflow: hidden;
}

.container ul{
    transition: 0.6s;
}

.container li {
    height: 30px;
    line-height: 30px;
    transition: 0.2s;
}

.container li.active{
    color:#fff;
    transform: scale(1.3);
} 

index.js

代码语言:javascript
复制
function parseLyrics() {
    let Things = lyrics.split('\n');
    let result = [];
    for (var i = 0; i < Things.length; i++) {
        let str = Things[i].split(']');
        let timeStr = str[0].substring(1);
        let timeArr = timeStr.split(':');
        let time = +timeArr[0] * 60 + +timeArr[1];
        let obj = {
            time: time,
            words: str[1],
        };
        result.push(obj);
    }
    return result;
}

let doms = {
    audio: document.querySelector('audio'),
    ul: document.querySelector('.container ul'),
    container: document.querySelector('.container'),

}

let lyricsData = parseLyrics();

function subscript() {
    let curTime = doms.audio.currentTime;
    for (var i = 0; i < lyricsData.length; i++) {
        if (curTime < lyricsData[i].time) {
            return i - 1;
        }
    }
    return lyricsData.length - 1;
}

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

initLyricsHtml();

let containerHeight = doms.container.clientHeight;
let liHeight = doms.ul.children[0].clientHeight;
let maxOffset = doms.ul.clientHeight - containerHeight;


function setOffset() {
    let index = subscript();
    let offset = liHeight * index + liHeight / 2 - containerHeight / 2;
    if (offset < 0) {
        offset = 0;
    }
    if (offset > maxOffset) {
        offset = maxOffset;
    }
    doms.ul.style.transform = `translateY(-${offset}px)`;

    let liActive = doms.ul.querySelector('.active');
    if (liActive) {
        liActive.classList.remove('active');
    }
    let li = doms.ul.children[index];
    if (li) {
        li.classList.add('active');
    }
}

doms.audio.addEventListener('timeupdate',setOffset);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档