2025年3月15日 星期六 甲辰(龙)年 月十四 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

用JS解析LRC格式的歌词,实现歌词同步滚动效果

时间:12-08来源:作者:点击数:11

用JS解析LRC格式的歌词

1、把歌词载入。

方法一:直接把歌词粘贴到一个textarea文本域中,然后把它设置为隐藏。

  • <!-- LRC歌词 -->
  • <textarea id="lrc_content" cols="30" style="display: none">
  • [ti:沙漠骆驼]
  • [ar:展展与罗罗]
  • [al:沙漠骆驼]
  • [by:0]
  • [offset:0]
  • [00:00.59]沙漠骆驼 - 展展与罗罗
  • [00:02.97]词:展展与罗罗
  • [00:04.46]曲:展展与罗罗
  • [00:26.45]我要穿越这片沙漠
  • [00:28.51]找寻真的自我
  • [00:30.50]身边只有一匹骆驼陪我
  • [00:34.96]这片风儿吹过
  • [00:37.15]那片云儿飘过
  • [00:39.26]突然之间出现爱的小河
  • [00:43.63]我跨上沙漠之舟
  • [00:45.71]背上烟斗和沙漏
  • [00:47.92]手里还握着一壶烈酒
  • [00:52.35]漫长古道悠悠
  • [00:54.51]说不尽喜怒哀愁
  • [00:56.56]只有那骆驼奔忙依旧
  • [01:01.08][02:23.81][04:13.30]什么鬼魅传说
  • [01:03.12][02:25.94][04:15.20]什么魑魅魍魉妖魔
  • [01:05.43][02:28.30][04:17.47]只有那鹭鹰在幽幽的高歌
  • [01:09.81][02:32.61][04:21.83]漫天黄沙掠过
  • [01:11.90][02:35.04][04:23.90]走遍每个角落
  • [01:14.05][02:36.99][04:26.20]行走在无尽的苍茫星河
  • [01:18.69][02:41.50][04:30.60]白天黑夜交错
  • [01:20.80][02:43.56][04:32.65]如此妖娆婀娜
  • </textarea>

再用JS把歌词读出来:

  • <script>
  • var lrc = document.getElementById("lrc_content").innerHTML;
  • </script>

方法二:用Ajax把后台的lrc文件载入。

  • var lrc = "";
  • function getLRC() {
  • var ajax = new XMLHttpRequest();
  • ajax.open("GET", "media/沙漠骆驼 - 展展与罗罗.lrc");
  • ajax.onreadystatechange = function () {
  • if (ajax.readyState == 4 && ajax.status == 200) {
  • lrc = ajax.responseText;
  • //console.log(lrc);
  • createLrcObj(lrc); // 调用createLrcObj函数,并传入lrc参数
  • }
  • };
  • ajax.send(null);
  • }
  • getLRC();

2、把LRC歌词解析为JS对象

代码如下:

  • var oLRC = {
  • ti: "", //歌曲名
  • ar: "", //演唱者
  • al: "", //专辑名
  • by: "", //歌词制作人
  • offset: 0, //时间补偿值,单位毫秒,用于调整歌词整体位置
  • ms: [] //歌词数组{t:时间,c:歌词}
  • };
  • function createLrcObj(lrc) {
  • if(lrc.length==0) return;
  • var lrcs = lrc.split('\n');//用回车拆分成数组
  • for(var i in lrcs) {//遍历歌词数组
  • lrcs[i] = lrcs[i].replace(/(^\s*)|(\s*$)/g, ""); //去除前后空格
  • var t = lrcs[i].substring(lrcs[i].indexOf("[") + 1, lrcs[i].indexOf("]"));//取[]间的内容
  • var s = t.split(":");//分离:前后文字
  • if(isNaN(parseInt(s[0]))) { //不是数值
  • for (var i in oLRC) {
  • if (i != "ms" && i == s[0].toLowerCase()) {
  • oLRC[i] = s[1];
  • }
  • }
  • }else { //是数值
  • var arr = lrcs[i].match(/\[(\d+:.+?)\]/g);//提取时间字段,可能有多个
  • var start = 0;
  • for(var k in arr){
  • start += arr[k].length; //计算歌词位置
  • }
  • var content = lrcs[i].substring(start);//获取歌词内容
  • for (var k in arr){
  • var t = arr[k].substring(1, arr[k].length-1);//取[]间的内容
  • var s = t.split(":");//分离:前后文字
  • oLRC.ms.push({//对象{t:时间,c:歌词}加入ms数组
  • t: (parseFloat(s[0])*60+parseFloat(s[1])).toFixed(3),
  • c: content
  • });
  • }
  • }
  • }
  • oLRC.ms.sort(function (a, b) {//按时间顺序排序
  • return a.t-b.t;
  • });
  • /*
  • for(var i in oLRC){ //查看解析结果
  • console.log(i,":",oLRC[i]);
  • }*/
  • }
  • createLrcObj(lrc);

解析后的歌词位于oLRC对象的ms数组中:

oLRC.ms[i].t 是第i行歌词的时间,以秒计;

oLRC.ms[i].c 是第i行歌词。

3、把解析后的歌词呈现在页面上

定义一个列表标签:

  • <ul id="lyric"></ul>

用JS把歌词写到标签里面:

  • function showLRC() {
  • var s="";
  • for(var i in oLRC.ms){//遍历ms数组,把歌词加入列表
  • s+='<li>'+oLRC.ms[i].c+'</li>';
  • }
  • document.getElementById("lyric").innerHTML = s;
  • }
  • showLRC();

以上完毕。

以下是完整代码:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <meta charset="utf-8">
  • <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
  • <title>带歌词歌曲</title>
  • <script src="../js/jquery-1.12.4.js"></script>
  • <style>
  • /* https://blog.csdn.net/yzy_csdn/article/details/84536646 */
  • div{
  • width:340px;
  • height:50px;
  • margin:0 auto;
  • overflow:hidden;
  • }
  • ul{
  • transition-duration: 600ms;
  • }
  • ul, li{
  • list-style:none;
  • padding: 0;
  • margin: 0;
  • }
  • .aplayer-lrc-contents li.on{
  • color: #0e90d2;
  • }
  • .aplayer-lrc-contents li p{
  • overflow: hidden;
  • text-overflow: ellipsis;
  • height: 16px;
  • line-height: 16px;
  • -webkit-line-clamp: 1;
  • -webkit-box-orient: vertical;
  • display: -webkit-box;
  • text-align: center;
  • margin-top: 0;
  • margin-bottom: 16px;
  • }
  • audio{
  • margin-top: 10px;
  • }
  • .aplayer-lrc:after,.aplayer-lrc:before {
  • position: absolute;
  • z-index: 1;
  • display: block;
  • overflow: hidden;
  • content: ' ';
  • width: 100%
  • }
  • .aplayer-lrc:before {
  • top: 25px;
  • height: 4%;
  • background: -webkit-linear-gradient(top,#fff 0,rgba(255,255,255,0) 100%);
  • background: -webkit-gradient(linear,left top,left bottom,from(white),to(rgba(255,255,255,0)));
  • background: linear-gradient(to top,#fff 0,rgba(255,255,255,0) 100%);
  • filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#00ffffff', GradientType=0 )
  • }
  • /*.aplayer-lrc:after {*/
  • /*bottom: 0;*/
  • /*height: 33%;*/
  • /*background: -webkit-linear-gradient(bottom,#fff 0,rgba(255,255,255,0) 100%);*/
  • /*background: -webkit-gradient(linear,left bottom,left top,from(white),to(rgba(255,255,255,0)));*/
  • /*background: linear-gradient(to top,#fff 0,rgba(255,255,255,0) 100%);*/
  • /*filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff', GradientType=0 )*/
  • /*}*/
  • </style>
  • </head>
  • <body>
  • <div class="aplayer-lrc">
  • <ul id="lrclist" class="aplayer-lrc-contents" style="transform: translateY(0px);"><!-- 保证歌词在正中间 -->
  • </ul>
  • </div>
  • <audio id="audio" src="music/找一个字代替.mp3" controls="controls" autoplay></audio>
  • <script>
  • var lrc = "";
  • function getLRC() {
  • var ajax = new XMLHttpRequest();
  • ajax.open("GET", "lrc/找一个字代替.lrc");
  • ajax.onreadystatechange = function () {
  • // if (ajax.readyState === 4 && ajax.status === 200) {
  • // lrc = ajax.responseText;
  • // // document.getElementById("lyric1").innerHTML = lrc;
  • // createLrcObj(lrc);
  • // }
  • // if (ajax.readyState !== 4 && ajax.status === 404) {
  • // console.log(ajax.status);
  • // document.getElementById("lrclist").innerHTML = "<li class='on'><p>"+"暂无歌词"+"</p></li>";
  • // // ul.innerHTML += "<li><p>"+"暂无歌词"+"</p></li>";//ul里填充歌词
  • // }
  • // 判断响应是否完成:XMLHttpRequest 对象的 readystate属性值为4的时候
  • if ( ajax.readyState === 4 ) {
  • //再判断是否可用 :XMLHttpRequest 对象的 status 属性为值 200
  • if ( ajax.status === 200 ) {
  • lrc = ajax.responseText;
  • createLrcObj(lrc);
  • } else {
  • document.getElementById("lrclist").innerHTML = "<li class='on'><p>"+"暂无歌词"+"</p></li>";
  • }
  • }
  • };
  • ajax.send(null);
  • }
  • getLRC();
  • var oLRC = {
  • ti: "", //歌曲名
  • ar: "", //演唱者
  • al: "", //专辑名
  • by: "", //歌词制作人
  • offset: 0, //时间补偿值,单位毫秒,用于调整歌词整体位置
  • ms: [] //歌词数组{t:时间,c:歌词}
  • };
  • function createLrcObj(lrc) {
  • if (lrc.length === 0) return;
  • var lrcs = lrc.split('\n');//用回车拆分成数组
  • for (var i in lrcs) {//遍历歌词数组
  • if (lrcs.hasOwnProperty(i)) {
  • lrcs[i] = lrcs[i].replace(/(^\s*)|(\s*$)/g, ""); //去除前后空格
  • var t_lrc = lrcs[i].substring(lrcs[i].indexOf("[") + 1, lrcs[i].indexOf("]"));//取[]间的内容
  • var s_text = t_lrc.split(":");//分离:号前后的文字
  • if (isNaN(parseInt(s_text[0]))) { //不是数值,基本上是歌曲名、作者等信息
  • for (var j in oLRC) {
  • if (j !== "ms" && j === s_text[0].toLowerCase()) {
  • oLRC[j] = s_text[1];
  • }
  • }
  • } else { //是数值,基本上就是歌词时间点
  • var arr = lrcs[i].match(/\[(\d+:.+?)\]/g);//提取时间字段,可能有多个
  • var start = 0;
  • for (var lrc_position in arr) {
  • if (arr.hasOwnProperty(lrc_position)) {
  • start += arr[lrc_position].length; //计算歌词位置
  • }
  • }
  • var content = lrcs[i].substring(start);//获取歌词内容
  • for (var k in arr) {
  • if (arr.hasOwnProperty(k)) {
  • var t = arr[k].substring(1, arr[k].length - 1);//取[]间的内容
  • var s = t.split(":");//分离:前后文字
  • oLRC.ms.push({//对象{t:时间,c:歌词}加入ms数组
  • t: parseFloat(s[0].substr(0,2)) * 60 + parseFloat(s[1].substring(0,6)),//注意转换成number格式
  • // t: (parseFloat(s[0]) * 60 + parseFloat(s[1])).toFixed(3),
  • c: content
  • });
  • }
  • }
  • }
  • }
  • }
  • oLRC.ms.sort(function (a, b) {//按时间顺序排序
  • return a.t - b.t;
  • });
  • // var lrc_result = "";
  • var lrcTime = [];//歌词对应的时间数组
  • var ul = $("#lrclist")[0];//获取ul
  • for (var n in oLRC.ms) {//遍历ms数组,把歌词加入列表
  • // lrc_result += '<li>' + oLRC.ms[n].c + '</li>';
  • // document.getElementById("lyric").innerHTML = lrc_result;
  • ul.innerHTML += "<li><p>"+oLRC.ms[n].c+"</p></li>";//ul里填充歌词
  • }
  • // console.log(oLRC.ms[0].t); // 时间00:00.231中的0.231
  • // console.log(oLRC.ms.length);
  • // for(var result in oLRC){ //查看解析结果
  • // // console.log(result,":",oLRC[result]);
  • // }
  • for(var x=0;x< oLRC.ms.length; x++){
  • lrcTime[x] = oLRC.ms[x].t;
  • }
  • lrcTime[oLRC.ms.length] = lrcTime[oLRC.ms.length-1] + 3;//如不另加一个结束时间,到最后歌词滚动不到最后一句
  • var $li = $("#lrclist>li");//获取所有li
  • var currentLine = 0;//当前播放到哪一句了
  • var currentTime;//当前播放的时间
  • var audio = document.getElementById("audio");
  • var ppxx;//保存ul的translateY值
  • audio.ontimeupdate = function() {//audio时间改变事件
  • currentTime = audio.currentTime;
  • for (j=currentLine, len=lrcTime.length; j<len; j++){ // len=50
  • if (currentTime<lrcTime[j+1] && currentTime>lrcTime[j]){
  • currentLine = j;
  • // ppxx = 250-(currentLine*32);
  • ppxx = -currentLine*32;
  • ul.style.transform = "translateY("+ppxx+"px)";
  • $li.get(currentLine-1).className="";
  • // console.log("on"+currentLine);
  • $li.get(currentLine).className="on";
  • break;
  • }
  • }
  • };
  • audio.onseeked = function() {//audio进度更改后事件
  • currentTime = audio.currentTime;
  • console.log(" off"+currentLine);
  • $li.get(currentLine).className="";
  • for (k=0, len=lrcTime.length; k<len; k++){
  • if (currentTime<lrcTime[k+1] && currentTime<lrcTime[k]){
  • currentLine = k;
  • break;
  • }
  • }
  • };
  • }
  • </script>
  • </body>
  • </html>

效果:

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐