|
|
请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 马黑黑 于 2022-9-17 11:33 编辑
效果请查看:请跟我来
一、CSS
使用背景移动的方式令lrc歌词产生演唱进度动感,#lrc 盒子充满黑科技:
#lrc {
position: absolute;
top: 100px;
font: bold 2em sans-serif;
color: transparent;
letter-spacing: 2px;
background: linear-gradient(-90deg, darkred, pink) 100% 100% / 200% 200%;
background-clip: text;
-webkit-background-clip: text;
}
红色那句,设置线性渐变,第一个颜色 darkred(深红色)模拟进度着色,第二个颜色 pink(粉红色)是歌词基本色(但会发生渐变效果)。后面的两组数字,第一组是 background-position(背景位置),第二组是 background-size(背景大小)。蓝色那两句,设置背景以文本为剪裁路径,即仅在文本上显示背景色。
#lrc 盒子不调用 @keyframes 关键帧动画,该工作将由 JS 完成。
@keyframes 关键帧动画比较简单,但相同的内容设计了两组,这是将来JS反复调用关键帧动画最廉价的方式:
@keyframes bgMove1 { from { background-position: 0 0; } to { background-position: -100% 0; } }
@keyframes bgMove2 { from { background-position: 0 0; } to { background-position: -100% 0; } }
因为我们前面使用的渐变背景方向是 -90deg,所以,这里,令背景位置从 0% 走到 -100% 。
二、JS
为了让歌词在被唱到的时段里能稳定运行关键帧动画,需要改进以前花潮lrc歌词同步的机制,做到,在这个时段里,歌词只上屏一次(以前的机制是在当句歌词演唱期间,当句歌词不停地上屏,因为是同一句歌词、同一个位置,肉眼感觉不到)。所以要加入一个判断机制。我的做法是,设计一个变量 mKey,该变量作为用以输出歌词的依据,它输出歌词前与 audio 的 timeupdate 事件配合完成判断即其他工作,它输出一句歌词后自动累进,为下一句歌词做准备。mKey 和另外的变量声明在这里:
let mKey = 0, mSeek = false, mFlag = true;
初始值肯定是 0,随后它会改变。其他变量在此一并说明:
mSeek - 进度被人为改变的变量,此变量现在可以删掉,定稿后用不上它
mFlag - 用以判断调用哪一个关键帧动画的依据,请结合前面CSS相关说明帮助理解
下来处理歌词输出的问题。
先看 audio 控件 timeupdate 监听事件:
aud.addEventListener('timeupdate', () => {
//其他代码
for(j=0; j<lrcAr.length; j++) {
if(aud.currentTime >= lrcAr[j][0]) { // ①
if(mKey === j) showLrc(lrcAr[j][2]); //②
else continue; //③
}
}
});
这里使用 for 语句循环歌词数组 lrcAr,如果 ① 当前播放时间与数组的时间信息匹配,则,②,如果当前 mKey 变量的值与循环到的匹配了歌句时间信息的 j 绝对相等(===,两个也成,==),就调用显示歌词函数 showLrc(参数) ,否则,③,在当前句演唱期间,跳出该次比对机制。
再看歌词输出函数 showLrc(time) :
let showLrc = (time) => {
lrc.style.animation = (mFlag ? 'bgMove1 ' : 'bgMove2 ') + time + 's linear forwards'; //根据 mFlag 的值给 animation 指定名称,同时进行其他赋值
lrc.innerHTML = lrcAr[mKey][1]; //输出歌词
mKey += 1; //mKey变量累进
mFlag = !mFlag; //变量值互反以保证下一次调用另外一个动画
}
这个函数需要一个参数 time,time 参数是被带入参数,它指向关键帧动画时长 duration(dur),每一句歌词演唱所用的时间不同,并且,在人为调节播放进度后,调节到的那一句剩余播放时间又不等于该句记录的总用时,所以需要这个 time 变量。这个变量,在自然播放时,timeupdate 事件会给出 lrcAr 数组记录的时间:
if(mKey === j) showLrc(lrcAr[j][2]); //②
lrcAr[j][2] 就是 lrcAr 数组 第 j 句 第 3 个成语的信息。
而当是手动,或因循环播放,调整了播放进度——
let calcKey = () => {
for(j = 0; j < lrcAr.length; j ++) { //循环歌词数组
if(aud.currentTime <= lrcAr[j][0]) { //如果被调整后的播放进度时间小于等于第 j 个数组的记录时间
mKey = j - 1; //则给 mKey 变量赋值 :减 1 才是调节到的那一句
break; //条件成立跳出循环
}
}
if(mKey <0) mKey = 0; //非手工调节时,如,播放完了重播,也同样触发进度被调节的行为,此时得出的 mKey 会小于 0
let mtime = lrcAr[mKey][2] - (aud.currentTime - lrcAr[mKey][0]);
showLrc(mtime);
}
在上面 calcKey() 函数里,最后的两句红色代码,计算手工调整进度后调节到的当句歌词所剩余的播放时间,然后调用 showLrc(time) 函数。这个函数除了干这个事,还有更核心的工作,就是计算调整进度之后,应播放的歌词是哪一句,找出来并赋值给 mKey 变量,完成这事,也需要循环一次 lrcAr 歌词数组,解释看上面的注释文本。
calcKey() 函数在什么时候执行?最省事的实现机制是利用 audio 的 seeked 事件,它和 seeking 事件一样,都会在播放进度被人为或自动重播时发生,seeked 在改变完成时触发,seeking在改变发生时触发,用哪一个都差不多,我选择 seeked:
aud.addEventListener('seeked', () => calcKey());
这是监听 seeked 事件,当手动调整了播放进度,或自然播放结束重新播放时,都会调用 calcKey() 函数,以保证 mKey 变量的值是我们所希望的。这样就解决了音频的播放进度被调控时,歌词着色能相对完好得以维持。
最后还需要考虑手动暂停/播放的歌词着色动画问题,这个简单,在设置按钮的函数里加入关键帧动画的播放/暂停即可:
let mState = () => aud.paused ? (btnplay.style.display = 'block', btnpause.style.display = 'none', lrc.style.animationPlayState = 'paused') : (btnplay.style.display = 'none', btnpause.style.display = 'block', lrc.style.animationPlayState = 'running');
貌似小小的功能,里面却充满着玄妙,希望大家能读懂。祝今日好心情!
|
评分
-
| 参与人数 3 | 威望 +100 |
金钱 +200 |
经验 +100 |
收起
理由
|
加林森
| + 30 |
+ 60 |
+ 30 |
很给力! |
红影
| + 50 |
+ 100 |
+ 50 |
赞一个! |
梦缘
| + 20 |
+ 40 |
+ 20 |
很给力! |
查看全部评分
|