Web前端—(原生JS)歌词滚动效果

歌词滚动效果实现

  • 歌词滚动效果
    • HTML部分
    • CSS部分
    • JS部分
      • 解析歌词字符串,得到歌词的对象数组
      • 计算在当前情况下,播放器播放到第几秒的情况
      • 创建歌词元素
      • 设置ul元素的偏移量
      • 最后对时间变化的事件进行监听
      • 完整JS代码

歌词滚动效果

  • 实现效果如图所示:

在这里插入图片描述

首先准备一个歌曲MP3文件,以及歌词,将歌词放入一个data.js文件中。
在这里插入图片描述

  • 歌词内容如下所示:
    在这里插入图片描述

HTML部分

  • 歌词采用ul-li的结构进行展示
  • 导入相应的css和js文件
  • 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./css/index.css">
</head>
<body>
    <audio src="./assets/薛之谦 - 狐狸.mp3" controls></audio>
    <div class="container">
        <ul>           
        </ul>
    </div>

    <script src="./js/data.js"></script>
    <script src="./js/index.js"></script>
</body>
</html>

CSS部分

  • 由于CSS属性变化本身没有动画效果,因此这里采用transition属性实现其动画效果
  • transition属性只针对于数值嘞的属性有效
  • 代码如下:(大家可以根据自己的喜好设置样式)
*{
    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.3s;
    
}
.container li{
    height: 30px;
    line-height: 30px;
    transition: 0.3s;
    list-style: none;
    
}
.container li.active{
    color: #fff;
    transform: scale(1.2);
}

JS部分

解析歌词字符串,得到歌词的对象数组

// 解析时间字符串
function parseTime(timeStr){
    let parts = timeStr.split(':');
    return +parts[0]*60 + +parts[1];
}
/**
 * 解析歌词字符串,得到歌词的对象数组
 * 每个歌词对象 
 * {time: 开始时间, words:歌词内容}
 */
function parseLrc(){
    var result = [];
    var lines = lrc.split('\n'); // 字符串数组
    for(let i = 0; i < lines.length; i++){
        // 遍历lines
        let str = lines[i]; //每一句歌词字符串
        let parts = str.split(']'); //分割
        let timeStr = parts[0].substring(1); //截取时间
        var obj ={
            time:parseTime(timeStr),
            words: parts[1]
        }
        result.push(obj);
    }
    return result;
}

var lrcData = parseLrc();

计算在当前情况下,播放器播放到第几秒的情况

/**
 * 计算在当前情况下,播放器播放到第几秒的情况
 * lrcData数组中应该高亮显示的歌词下标
 */
function findIndex(){
    // 获取播放器的当前时间
    let curTime = doms.audio.currentTime;
    for(let i = 0; i<lrcData.length; i++){
        if(curTime<lrcData[i].time){
            return i-1;
        }
    }
    // 如果没有任何一句歌词显示,则返回-1
    // 如果找遍了都没有找到,说明播放到最后一句
    return lrcData.length-1;
}

创建歌词元素

// 创建歌词元素
function createLrcElement(){
    for(let i=0; i<lrcData.length; i++){
        let li = document.createElement('li');
        li.textContent = lrcData[i].words;
        doms.ul.appendChild(li);
    }
}

设置ul元素的偏移量

// 容器高度
var containerHeight = doms.container.clientHeight;
// li高度
var liHeight = doms.ul.children[0].clientHeight;
// 最大高度
var maxOffset = doms.ul.clientHeight - containerHeight;


// 设置ul元素的偏移量
function setOffset(){
    let index = findIndex();
    var offset = liHeight * index + liHeight/2 - containerHeight/2;
    if(offset < 0){
        offset = 0;
    }
    if(offset > maxOffset){
        offset = maxOffset;
    }
    doms.ul.style.transform = `translateY(-${offset}px)`;

    // 去掉之前的active样式
    let li1 = doms.ul.querySelector('.active');
    if(li1){
        li1.classList.remove('active');
    }

    let li2 = doms.ul.children[index];
    if(li2){
        li2.classList.add('active');
    }

}

最后对时间变化的事件进行监听

doms.audio.addEventListener('timeupdate', setOffset);

如果大家没有MP3文件或者歌词的话,我会上传我的资源,可以自行下载。

完整JS代码

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

// 解析时间字符串
function parseTime(timeStr){
    let parts = timeStr.split(':');
    return +parts[0]*60 + +parts[1];
}

/**
 * 解析歌词字符串,得到歌词的对象数组
 * 每个歌词对象 
 * {time: 开始时间, words:歌词内容}
 */
function parseLrc(){
    var result = [];
    var lines = lrc.split('\n'); // 字符串数组
    for(let i = 0; i < lines.length; i++){
        // 遍历lines
        let str = lines[i]; //每一句歌词字符串
        let parts = str.split(']'); //分割
        let timeStr = parts[0].substring(1); //截取时间
        var obj ={
            time:parseTime(timeStr),
            words: parts[1]
        }
        result.push(obj);
    }
    return result;
}

var lrcData = parseLrc();


/**
 * 计算在当前情况下,播放器播放到第几秒的情况
 * lrcData数组中应该高亮显示的歌词下标
 */
function findIndex(){
    // 获取播放器的当前时间
    let curTime = doms.audio.currentTime;
    for(let i = 0; i<lrcData.length; i++){
        if(curTime<lrcData[i].time){
            return i-1;
        }
    }
    // 如果没有任何一句歌词显示,则返回-1
    // 如果找遍了都没有找到,说明播放到最后一句
    return lrcData.length-1;
}

// 创建歌词元素
function createLrcElement(){
    for(let i=0; i<lrcData.length; i++){
        let li = document.createElement('li');
        li.textContent = lrcData[i].words;
        doms.ul.appendChild(li);
    }
}
createLrcElement()

// 容器高度
var containerHeight = doms.container.clientHeight;
// li高度
var liHeight = doms.ul.children[0].clientHeight;
// 最大高度
var maxOffset = doms.ul.clientHeight - containerHeight;


// 设置ul元素的偏移量
function setOffset(){
    let index = findIndex();
    var offset = liHeight * index + liHeight/2 - containerHeight/2;
    if(offset < 0){
        offset = 0;
    }
    if(offset > maxOffset){
        offset = maxOffset;
    }
    doms.ul.style.transform = `translateY(-${offset}px)`;

    // 去掉之前的active样式
    let li1 = doms.ul.querySelector('.active');
    if(li1){
        li1.classList.remove('active');
    }

    let li2 = doms.ul.children[index];
    if(li2){
        li2.classList.add('active');
    }

}

// 事件监听
doms.audio.addEventListener('timeupdate', setOffset);```

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/502097.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

防静电工作台:静电敏感环境下的必备设备

在当今的电子制造、精密仪器制造、化学实验室等领域&#xff0c;静电敏感性已成为一个不可忽视的问题。静电可能对设备和操作人员造成严重损害&#xff0c;因此防止静电的产生和传导是至关重要的。在这样的背景下&#xff0c;防静电工作台应运而生&#xff0c;成为这些领域中不…

【蓝桥杯省赛真题37】python农田划分 中小学青少年组蓝桥杯比赛 算法思维python编程省赛真题解析

目录 python农田划分 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python农田划分 第十三届蓝桥杯青少年组python比赛省赛真题 一、题目要求…

kafka学习笔记02(小滴课堂)

Kafka命令行生产者发送消息和消费者消费消息实战 已存在的kafka不能重复创建。 broker设置的是1&#xff0c;factor大于broker了&#xff0c;所以报错。 生产者发送消息&#xff1a; kafka列表出现了新的kafka。 我们使用这个kafka。 我们启动消费者&#xff1a; 我们现在不从…

【dll解密】Dll加壳保护方案分析修复

分析背景 NGame游戏海外版出现了破解版&#xff0c;该版本在dump出游戏的dll中不能直接通过反编译工具查看修改后的游戏代码&#xff0c;导致无法确定外挂修改的直接逻辑点。本文主要针对AssemblyCSharp.dll模版&#xff0c;分析其dll保护的方法。 分析过程 1、拿到Encrypt_As…

【动手学深度学习-pytorch】 9.4 双向循环神经网络

在序列学习中&#xff0c;我们以往假设的目标是&#xff1a; 在给定观测的情况下 &#xff08;例如&#xff0c;在时间序列的上下文中或在语言模型的上下文中&#xff09;&#xff0c; 对下一个输出进行建模。 虽然这是一个典型情景&#xff0c;但不是唯一的。 还可能发生什么其…

【LVGL-使用SquareLine Studio设计器 】

LVGL-使用SquareLine Studio设计器 ■ 简介■ 安装■ SquareLine Studio移植到工程 ■ 简介 SquareLine Studio 设计器是一个付费软件。 ■ 安装 SquareLine Studio 设计器的下载地址 我们点击“WINDOWS”下载 SquareLine Studio 设计器&#xff0c;下载完成之后我们就会得到…

GIS硬核入门,二维地图是如何使用WGS84坐标系来转换成墨卡托投影的xyz地图瓦片切片的详细原理

前言 二维地图一般分成两种&#xff0c;一种是简化的道路地图视图&#xff0c;一种是卫星拍摄的高清影像地图。 四种坐标概念理解&#xff1a; 经度和纬度&#xff0c;对应地球上唯一的一个点&#xff08;例如&#xff1a;Google 使用世界大地测量系统 WGS84 标准&#xff0…

Day49:WEB攻防-文件上传存储安全OSS对象分站解析安全解码还原目录执行

目录 文件-解析方案-目录执行权限&解码还原 目录执行权限 解码还原 文件-存储方案-分站存储&OSS对象 分站存储 OSS对象存储 知识点&#xff1a; 1、文件上传-安全解析方案-目录权限&解码还原 2、文件上传-安全存储方案-分站存储&OSS对象 文件-解析方案-目…

数据结构之二叉树由浅入深(四)

目录 题外话 正题 第一题 第一题思路 第一题代码详解 第二题 第二题思路 第二题代码详解 第三题 第三题思路 第三题代码及详解 第四题 第四题思路 第四题代码及详解 第五题 第五题思路 第五题代码及详解 题外话 本来昨天就想写完这篇文章,怎么样是不是很大胆?…

ttkbootstrap界面美化系列之Notebook(四)

在简单的界面设计中&#xff0c;Notebook也是常用的组件之一&#xff0c;Notebook组件的引入可以根据标签来切换不同的界面。使得界面更有层次感&#xff0c;不必都挤在一个界面上。在tkinter中就有Notebook组件&#xff0c;在ttkbootstrap中&#xff0c;同样也对Notebook进行了…

Flutter开发之objectbox

Flutter开发之objectbox 在之前进行iOS开发的时候使用WCDB去进行管理数据库很方便&#xff0c;它支持ORM&#xff08;Object-Relational Mapping&#xff0c;对象关系映射&#xff09;&#xff0c;用于实现面向对象编程语言里不同类型系统的数据之间的转换。 那么在Flutter开发…

d3dcompiler_43.dll丢失的解决方法,快速解决win10系统错误问题

当系统提示“d3dcompiler_43.dll缺失”时&#xff0c;意味着计算机中缺少这一关键性动态链接库文件。该文件作为DirectX 3D编译器组件的一部分&#xff0c;对于许多依赖于DirectX技术的应用程序或游戏至关重要。这个错误通常会导致游戏或应用程序无法正常运行。为了解决这个问题…

java Web洗衣店管理系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 洗衣店管理系统是一套完善的web设计系统&#xff0c;对理解JSP java 编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&#xff0c;使用…

记一次dubbo provider获取不到dubbo.tag问题排查

1. 背景 项目里通过dubbo.taggray传递灰度标&#xff0c;但是上游consumer已经在attachment里面设置dubbo.gray了&#xff0c;下游却拿不到 2. 排查过程 2.1. 前提 先把源码下载下来&#xff0c;方便排查 详细可见&#xff1a;tps://blog.csdn.net/qq_26012495/article/det…

9、jenkins微服务持续集成(一)

文章目录 一、流程说明二、源码概述三、本地部署3.1 SpringCloud微服务部署本地运行微服务本地部署微服务3.2 静态Web前端部署四、Docker快速入门一、流程说明 Jenkins+Docker+SpringCloud持续集成流程说明 大致流程说明: 开发人员每天把代码提交到Gitlab代码仓库Jenkins从G…

烟草行业率先布局新质生产力,中国烟草11省40家公司已上线实在Agent数字员工

为了更好赋能烟草行业数智化转型发展需求&#xff0c;各地烟草集团公司都开始陆续展开数智化赋能培训。近日&#xff0c;杭州烟草临安分公司举办“人工智能作为企业新质生产力发展的落地探索”论坛会议&#xff0c;实在智能受邀出席&#xff0c;聚焦“TARS大模型及实在Agent数字…

武汉星起航:引领跨境电商新潮流,一站式服务助合作伙伴成功起航

武汉星起航电子商务有限公司是一家集自营亚马逊跨境电商与亚马逊卖家孵化服务于一体的公司。在创始人张振邦先生的引领下&#xff0c;公司凭借深厚的电子商务运营经验和对行业的深刻洞察&#xff0c;积极响应国家大力发展跨境电商行业的号召&#xff0c;为刚起步和未起步的合作…

vue3封装Element表格自适应

表格高度自适应 分页跟随表格之后 1. 满屏时出现滚动条 2. 不满屏时不显示滚动条 坑 表格设置maxHeight后不出现滚动条 解决方案 表格外层元素设置max-height el-table–fit 设置高度100% .table-box {max-height: calc(100% - 120px); } .el-table--fit {height: 100%; }示例代…

会声会影剪刀为什么灰色 会声会影分割素材的方法 会声会影视频制作教程 会声会影2023旗舰版下载 会声会影快捷键

会声会影是一款操作简单&#xff0c;功能齐全&#xff0c;适合新手使用的视频剪辑软件。在使用会声会影剪辑的过程中&#xff0c;我们一般需要使用【剪刀工具】&#xff0c;但有时会声会影剪刀是灰色无法使用的状态&#xff0c;这个时候该怎么办呢&#xff1f;本文将为大家介绍…

pytest--python的一种测试框架--简介

一、什么是接口测试 接口测试是软件测试的一种类型&#xff0c;用于验证不同软件系统之间的接口是否按照设计规范进行通信和交互。接口测试通常涉及以下方面&#xff1a; 功能性验证&#xff1a;确认接口按照规范执行预期的功能。 性能测试&#xff1a;验证接口在不同负载条…