用JS解析LRC格式的歌詞,實現歌詞同步滾動效果

用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();

以上完畢。

以下是結合這個頁面加工後的完整代碼:https://blog.csdn.net/yzy_csdn/article/details/84536646

<!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>

效果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章