《当你老了》帖子代码分析
本帖最后由 马黑黑 于 2022-6-5 08:28 编辑这个帖子,使用的歌词同步机制是我半年前回北方老家时做的,当时一天一醉,代码质量估计不高,但基本能正常工作。不多说,先上帖子代码,后面以回复方式做一些简单分析:
<style>
/* 界面及音乐控制 */
.mama { left: -339.5px; width: 1275px; height: 717px; background: #eee url('https://638183.freep.cn/638183/t22/51/sea.jpg') no-repeat; position: relative; }
.goose { position: absolute; bottom: 30px; width: 200px; cursor: pointer; }
.meter { position: absolute; left: 50%; bottom: 140px; transform: rotate(-15deg); cursor: pointer; }
/* 歌词同步 */
#lrcDiv { left: 50%; top: 50%; width: 340px; height: 60px; overflow: hidden; position: absolute; padding: 8px; }
#lrcDiv ul, lrcli { margin: 0; padding: 0;}
#lrcUl { position: absolute; top: 0; }
#lrcUl li { height: 24px; font: normal 20px / 24px sans-serif; color: #64b4d5; text-shadow: 1px 1px 1px #333; list-style-type: none; }
#myplayer { outline: none; list-style-type: none; }
</style>
<div class="mama">
<div id="lrcDiv"><ul id="lrcUl"></ul></div>
<img class="goose" src="https://638183.freep.cn/638183/t22/51/goose.gif" alt="" />
<meter class="meter" min="0" max="100" low="33" high="66" optimum="80" value="0"></meter>
</div>
<audio class="aud" src="https://music.163.com/song/media/outer/url?id=1894114925.mp3" autoplay="autoplay" loop="loop"></audio>
<script>
//元素句柄
let aud = document.querySelector('.aud'),
meter = document.querySelector('.meter'),
goose = document.querySelector('.goose'),
lrcUl = document.getElementById('lrcUl');
//lrc歌词
let lrcAr=[
['0:01','词 : William Butler Yeats'],
['0: 10','曲 : 趙照'],
['0: 20','石栋颖 & 韩甜甜'],
['0:28','lrc记录 : 韩苦'],
['0:31','当你老了'],
['0:34','头发白了'],
['0:39','睡意昏沉'],
['0:45','当你老了'],
['0:49','走不动了'],
['0:52','炉火旁打盹'],
['0:56','回忆青春'],
['1:00','多少人曾爱你青春欢唱的时辰'],
['1:07','爱慕你的美丽'],
['1:10','假意或真心'],
['1:14','只有一个人还爱你虔诚的灵魂'],
['1:21','爱你苍老的脸上的皱纹'],
['1:58','当你老了'],
['2:01','头发白了'],
['2:05','睡意昏沉'],
['2:12','当你老了'],
['2:15','走不动了'],
['2:18','炉火旁打盹'],
['2:23','回忆青春'],
['2:27','多少人曾爱你青春欢唱的时辰'],
['2:33','爱慕你的美丽'],
['2:37','假意或真心'],
['2:40','只有一个人还爱你虔诚的灵魂'],
['2:47','爱你苍老的脸上的皱纹'],
['2:54','当我老了'],
['2:56','当你老了',''],
['2:58','我真希望'],
['3:00','这首歌是唱给你的']
];
//处理lrc歌词数组:时间转换成秒、歌词放入li标签
for(j=0; j<lrcAr.length; j++){
lrcAr = toSec(lrcAr);
lrcUl.innerHTML += "<li id='li" + lrcAr + "'>" + lrcAr + "</li>";
}
//lrc时间信息转为秒
function toSec(lrcTime) {
let tmpAr = lrcTime.split(':');
lrcTime = tmpAr * 60 + parseInt(tmpAr);
return lrcTime;
}
aud.addEventListener('timeupdate', () => {
let prog = 100 * aud.currentTime / aud.duration;
goose.style.transform = 'translate(' + prog * 11 + 'px)';
meter.value = prog;
//歌词同步
let tt = aud.currentTime;
for(j=0; j<lrcAr.length; j++){
if(tt > lrcAr){
if(j > 0){
let idxLast = lrcAr;
document.getElementById("li" + idxLast).style.color = "#64b4d5";
lrcUl.style.top ="-" + (j * 24 - 24) + "px"; //乘减依据: 行高设定
}
let idx = lrcAr;
document.getElementById("li" + idx).style.color = "#fff";
}
}
});
// 播放结束重置歌词样式
aud.onended = function() {
document.getElementById("li" + lrcAr).style.color = "#64b4d5";
lrcUl.style.top = 0;
this.play();
}
//音乐控制
meter.onclick = goose.onclick = () => aud.paused ? aud.play() : aud.pause();
</script>
本帖最后由 马黑黑 于 2022-6-5 08:38 编辑
先说说lrc歌词结构。它以数组方式存放,代码写成酱紫:
//lrc歌词
let lrcAr=[
['0:01','词 : William Butler Yeats'],
['0: 10','曲 : 趙照'],
['0: 20','石栋颖 & 韩甜甜'],
['0:28','lrc记录 : 韩苦'],
//......
['0:31','当你老了']
];
这是二维数组,每一句歌词一条记录。每条记录包含时间和歌词,其中,时间有分加秒组成,结构为 分:秒,例如零分零五秒,记为 0:05。每一条记录的结构要正确,不能有误,具体为 [‘时间','歌词'] ,且每一条记录结束是中括号后面要跟着小角逗号,但最后一句又不能有逗号!
顺带说一下,如果时间记为以下这个样纸,也是可以的:
['0:01:363','词 : William Butler Yeats'],
不过后面那个时间数,:363 部分,是被程序忽略的。
本帖最后由 马黑黑 于 2022-6-5 08:45 编辑
下面说说歌词显示字体大小相关的问题。
在CSS代码内,选择器 #lrcUl li 规定了字体,其中,注意这句,
font: normal 20px / 24px sans-serif;
24px 表示行高,它将影响JS移动歌词的决策。试看JS代码中,监听播放时间变化的函数里的歌词同步代码:
//歌词同步
let tt = aud.currentTime;
for(j=0; j<lrcAr.length; j++){
if(tt > lrcAr){
if(j > 0){
let idxLast = lrcAr;
document.getElementById("li" + idxLast).style.color = "#64b4d5";
lrcUl.style.top ="-" + (j * 24 - 24) + "px"; //乘减依据: 行高设定
}
let idx = lrcAr;
document.getElementById("li" + idx).style.color = "#fff";
}
}
注意有红色文本的那句,红色数字要与前面的行高一致。
此外,#lrcDiv 选择器的高度可以调整,不同的高度显示的行数将不一样,但请确保所设置的高度不割裂文本。
占位三 来学习,好久都没有制作同步的了,现在跟着制作一个出来玩玩。 加林森 发表于 2022-6-5 09:31
来学习,好久都没有制作同步的了,现在跟着制作一个出来玩玩。
又是手痒痒了{:4_170:} 马黑黑 发表于 2022-6-5 09:32
又是手痒痒了
逗是逗是,看见好玩的不玩一把就不舒服的。{:4_189:} 加林森 发表于 2022-6-5 09:39
逗是逗是,看见好玩的不玩一把就不舒服的。
有精气神 马黑黑 发表于 2022-6-5 09:47
有精气神
必须的 goose.style.transform = 'translate(' + prog * 11 + 'px)';
这里的11是怎么出来的?是算好大鹅要走过的距离的吧。 .meter好像没设置宽度,我忘记它的默认宽是多少了。100?
大鹅也没设置初始left,那就是直接从0位置走到1100了吧? 同步控制还能这么玩,这个设置真简便{:4_199:} 红影 发表于 2022-6-5 10:52
.meter好像没设置宽度,我忘记它的默认宽是多少了。100?
大鹅也没设置初始left,那就是直接从0位置走到11 ...
absolute定位时,没人left值是0;然后根据音乐播放进度步行,走到left为 1100px 时返回(因为prog变量是百分比的数值但没有百分号,乘上11是根据父元素尺寸和图片尺寸估算来着) 红影 发表于 2022-6-5 10:49
goose.style.transform = 'translate(' + prog * 11 + 'px)';
这里的11是怎么出来的?是算好大鹅要走过 ...
父元素的尺寸,宽度是 1275,减去图片的宽度,left值到1100是就差不多了 红影 发表于 2022-6-5 10:52
.meter好像没设置宽度,我忘记它的默认宽是多少了。100?
大鹅也没设置初始left,那就是直接从0位置走到11 ...
你可以用JS测一下它的宽度:meter.height 或 meter.clientHeight 红影 发表于 2022-6-5 10:54
同步控制还能这么玩,这个设置真简便
一切都需要相对靠谱的计算 马黑黑 发表于 2022-6-5 11:20
absolute定位时,没人left值是0;然后根据音乐播放进度步行,走到left为 1100px 时返回(因为prog变量是 ...
音乐播放进度可以用来驱动图片,其实你在用那个红色方块现实百分比跟随进度条的帖子就已经明示了,而我直到看到另外位置放置的大鹅才反应过来,我也太笨了点{:4_173:} 马黑黑 发表于 2022-6-5 11:22
父元素的尺寸,宽度是 1275,减去图片的宽度,left值到1100是就差不多了
大鹅宽度200,的确差不多{:4_173:} 马黑黑 发表于 2022-6-5 11:23
你可以用JS测一下它的宽度:meter.height 或 meter.clientHeight
这个,还没反应过来。 马黑黑 发表于 2022-6-5 11:24
一切都需要相对靠谱的计算
嗯嗯,明白了。谢谢黑黑的耐心解答{:4_187:}
页:
[1]
2