效果展示
跟隨歌曲時間同步滾動歌詞,並實現高亮效果
總體思路
- 獲取歌詞
- 解析歌詞
- 打印歌詞
- 同步歌詞
1. 獲取歌詞
用 ajax 和網易雲的 api 獲取的歌詞資源.(涉及到跨域問題,這里不贅述,主要講同步功能的思路)
2. 解析歌詞
步驟:
1. 新建數組 lrcArray
2. 提取歌詞 lrcGet
3. 用換行符把字符串 lrcGet分 割為數組 lrc
4. 遍歷 lrc
其中,遍歷 lrc 后的處理步驟
- 過濾
- 提取和轉化時間
- 提取歌詞
- 添加進數組 lrcArray
控制台返回的 lrcGet
lrc
js
var lrcArray = [];//新建數組,用於存放歌詞
var lrcGet = data.lrc.lyric;//提取歌詞
// console.log(lrcGet);
var lrc = lrcGet.split('\n');
// console.log(lrc);
$.each(lrc, function(i, item) {
//過濾空白文本
if (item.split(']')[1] == "" || item == "" || item.indexOf('作曲') !== -1 || item.indexOf('作詞') !== -1) {
return true;
}
//轉化時間
var timeStr = item.substring(item.indexOf("[") + 1, item.indexOf("]"));
var min = parseInt(timeStr.split(':')[0]) * 60;
var sec = parseFloat(timeStr.split(':')[1]);
var time = parseFloat((min + sec).toFixed(2));
//添加進數組
lrcArray.push({
t: time,
c: item.substring(item.indexOf(']') + 1)
});
});
3. 打印歌詞
控制台返回處理后的數組lrcArray如下:
html代碼
<div class="lyrics">
<ul class="lyricsList"></ul>
</div>
js
//顯示歌詞
//打印全部在頁面
var html = "";
$.each(lrcArray, function(i, v) {
html += '<li>' + v.c + '</li>';
});
$('.lyricsList').append(html);
4. 同步歌詞
$('#audio')[0].ontimeupdate = function() {
$.each(lrcArray, function(i, v) {
if ($('#audio')[0].currentTime >= lrcArray[i].t) {
$('.lyricsList').css('margin-top', '');//避免進度變動時數值產生混亂
$('.lyricsList li').eq(i).addClass('highlight');
$('.lyricsList li').eq(i).siblings().removeClass('highlight');
if (i > 2) {
$('.lyricsList').css('margin-top', (-i + 2) * 30 + 'px');
}
}
});
};
思路: audio 時間進度每更新一次,就同步一次該數組,把audio 的當前時間和數組每一項的時間作比較.當檢測到前者大於或等於后者,就高亮和滾動對應的歌詞.
關於高亮的思路
以代碼的角度:
以index(這里對應 i)為橋梁,只要符合條件,對應的 li 就會先被高亮后被消除高亮,一直到最后一個符合條件的 lrcArray[i].t
里的 i對應的 li被高亮,此時只會高亮而不會消除,等到 i+1 符合條件,i 的 先高亮后消除,i+1只高亮,以此迭代下去.
從樣式上看:
由於代碼執行飛速,以致肉眼不會看到先高亮后消除的過程,只會看到最后一個被高亮.
關於滾動的思路
html代碼
<div class="lyrics">
<ul class="lyricsList"></ul>
</div>
css 樣式
.lyrics {
height: 32%;
padding-top: 8px;
overflow: hidden;
}
.lyrics .lyricsList {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.lyrics .lyricsList li {
height: 30px;
line-height: 15px;
font-size: 12px;
}
js 代碼
var index = 0;
$('#audio')[0].ontimeupdate = function() {
if (this.currentTime >= parseFloat(lrcArray[index].t)) {
$('.lyricsList li').eq(index).addClass('highlight');
$('.lyricsList li').eq(index).siblings().removeClass('highlight');
if (index > 2) {
//添加 css 樣式以實現滾動效果
$('.lyricsList').css('margin-top', -(index - 2) * 30 + 'px');
}
index++;
}
};
js 滾動思路分析圖
從 i>2 起設置margin-top負值.
當滾動到 i=3對應的 li 節點后,margin-top 的值每次增加一個負的 li 的行高,即-30px,以實現推動效果。在高亮效果滾動到下一個 li的同時,ul 容器往上推動一個li行高,兩者作用下的效果為高亮位置保持不變。
注:
-
在條件代碼塊的第一行用
.css('margin-top', '')
消除樣式,避免每一次margin-top 值發生改變引起數值錯亂,避免 bug. -
以下在觸發進度條事件時,會發生同步錯誤.
原因:
當this.currentTime
突然變小,而 index 無法隨之改變,因此條件無法匹配.
當this.currentTime
突然變大, index也無法突變,只能遞增,會產生逐行高亮又消失,直到匹配到臨界值的情況.
涉及的 jq 方法總結
- dom 方法
- $(dom).eq(i) 返回第i 個;
- $(dom).siblings() dom的兄弟節點,即除了自己,借助該方法可實現兄弟節點之前的排他性樣式,如歌詞高亮.
- $(dom).empty() 清空所有子節點
- $(dom).css('屬性', ''); 消除某個屬性
- each遍歷中跳出循環的方法:
- return false;——跳出所有循環;相當於 javascript 中的 break 效果。
- return true;——跳出當前循環,進入下一個循環;相當於 javascript 中的 continue 效果
- 過濾空白文本和包含關鍵詞文本
if (item.split(']')[1] == "" || item == "" || item.indexOf('作曲') !== -1 || item.indexOf('作詞') !== -1) {
return true;
- 字符串
- str.split('\n')
- str.substring(str.indexOf("[") + 1, str.indexOf("]")) 提取[]中間的字符串
- str.indexOf(str,str)
- 數字
- str.parseInt(),str.parseFloat()
- num.toFixed(num)
- 數組
- arr.push(item)
完整代碼
<div class="lyrics">
<ul class="lyricsList"></ul>
</div>
.lyrics {
height: 32%;
padding-top: 8px;
overflow: hidden;
}
.lyrics .lyricsList {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.lyrics .lyricsList li {
height: 30px;
line-height: 15px;
font-size: 12px;
}
//歌詞高亮
.highlight {
color: #3effee;
text-shadow: 0 0 10px #ded1fc;
}
function parseLrc(data) {
// console.log(data);
var lrcArray = []; //新建數組,用於存放歌詞
var lrcGet = data.lrc.lyric; //提取歌詞
console.log(lrcGet);
var lrc = lrcGet.split('\n');
console.log(lrc);
$.each(lrc, function(i, item) {
//過濾空白文本
if (item.split(']')[1] == "" || item == "" || item.indexOf('作曲') !== -1 || item.indexOf('作詞') !== -1) {
return true;
}
//轉化時間
var timeStr = item.substring(item.indexOf("[") + 1, item.indexOf("]"));
var min = parseInt(timeStr.split(':')[0]) * 60;
var sec = parseFloat(timeStr.split(':')[1]);
var time = parseFloat((min + sec).toFixed(2));
//添加進數組
lrcArray.push({
t: time,
c: item.substring(item.indexOf(']') + 1)
});
});
console.log(lrcArray);
//顯示歌詞
var html = "";
$.each(lrcArray, function(i, v) {
html += '<li>' + v.c + '</li>';
});
$('.lyricsList').append(html);
//同步高亮歌詞
$('#audio')[0].ontimeupdate = function() {
$.each(lrcArray, function(i, v) {
if ($('#audio')[0].currentTime >= lrcArray[i].t) {
$('.lyricsList').css('margin-top', '');
$('.lyricsList li').eq(i).addClass('highlight');
$('.lyricsList li').eq(i).siblings().removeClass('highlight');
if (i > 2) {
$('.lyricsList').css('margin-top', (-i + 2) * 30 + 'px');
}
}
});
};
}
本文作者: 喬一亖
本文鏈接: https://www.cnblogs.com/joyce33/p/13376752.html
版權聲明: 本文版權歸作者和博客園共有,轉載請注明出處!如有問題或建議,請多多賜教,非常感謝。