原生lrc歌词同步新尝试
<div class="codebox" data-prev="1"><style>
#pa {
margin: 20px auto;
width: 1024px ;
height: 640px;
border: 1px solid gray;
display: grid;
place-items: center;
position: relative;
}
#wrapper {
position: absolute;
padding: 10px;
font: bold 2rem/1.2 sans-serif;
text-shadow: 1px 1px 1px gray;
bottom: 20px;
}
.char {
display: inline-block;
padding: 0 2px;
opacity: 0;
transform: translate(var(--x), var(--y));
animation: fadeIn 0.3s var(--delay) forwards;
}
audio { position: absolute; left: 20px; top: 20px; }
@keyframes fadeIn {
to {
transform: translate(0, 0);
opacity: 1;
}
}
</style>
<div id="pa">
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=3319366184" controls autoplay></audio>
<div id="wrapper">HUACHAO LRC</div>
</div>
<script>
const gc = `王睿卓 - 花田错\n我犯了错\n夜好深了 纸窗里怎么亮着\n那不是 彻夜等候 你为我点的烛火\n不过是 一次邂逅 红楼那一场梦\n我的山水 全部褪色 像被大雨洗过\n杯中景色鬼魅 我忘了我是谁\n心情就像夜凉如水\n手里握着蝴蝶杯 单飞 不醉不归\n花田里犯了错\n说好 破晓前忘掉\n花田里犯了错\n拥抱 变成了煎熬\n花田里犯了错\n犯错像迷恋镜花水月的无聊\n花田里犯了错\n请原谅我多情的打扰\n醉 怎么会喝醉\n美 因为你的美\n爱匆匆一瞥不过点缀\n飞 看大雪纷飞\n却 再也找不回\n被白雪覆盖那些青翠\n当时空成为拥有你\n唯一条件 我又醉\n琥珀色的月 结了霜的泪\n我会记得这段岁月\n花田里犯了错\n说好 破晓前忘掉\n花田里犯了错\n拥抱 变成了煎熬\n花田里犯了错\n犯错像迷恋镜花水月的无聊\n花田里犯了错\n请原谅我多情的打扰\n我的山水全部褪了色\n多情的打扰请原谅我\n不是彻夜为我点的火\n在那花田里我犯了错\n我的山水全部褪了色\n多情的打扰请原谅我\n不是彻夜为我点的火\n在那花田里我犯了错\n花田里犯了错\n说好 破晓前忘掉\n花田里犯了错\n拥抱 变成了煎熬\n花田里犯了错\n犯错像迷恋镜花水月的无聊\n花田里犯了错\n请原谅我多情的打扰\n我犯了错`;
const gcAr = lrc2HC(gc);
let curkey = 0, isSeeking = false;
aud.ontimeupdate = () => {
if(curkey > gcAr.length - 1) return;
if(aud.currentTime >= gcAr) {
const gap = gcAr?. ?? 0 - gcAr;
showLrc(gcAr, wrapper, gap);
}
};
aud.onended = () => {
curkey = 0;
aud.play();
}
aud.onseeked = () => calcKey();
function lrc2HC(text) {
let lrcAr = [];
let ar = text.trim().split('\n');
ar.sort();
let reg = /\[(\d+)[.:](\d+)[.:](\d+)\](.*)/;
ar.forEach(item => {
if(reg.test(item)) {
let result = item.match(reg);
let tmsg = parseInt(result) * 60 + parseInt(result) + parseInt(result) / 1000;
lrcAr.push(.trim()]);
}
});
return lrcAr ? lrcAr : ;
};
function calcKey() {
for (let j = 0; j < gcAr.length; j++) {
if (aud.currentTime <= gcAr) {
curkey = j - 1;
break;
}
}
if (curkey < 0) curkey = 0;
if (curkey > gcAr.length - 1) curkey = gcAr.length - 1;
let time = gcAr?. ?? 0 - gcAr;
isSeeking = false;
showLrc(gcAr, wrapper, time);
}
function showLrc(str, targetElm, time) {
if(isSeeking) return;
targetElm.innerHTML = '';
const chars = str.split('').map(c => c === ' ' ? ' ' : c);
const frg = document.createDocumentFragment();
chars.forEach((char, idx) => {
const span = document.createElement('span');
span.innerHTML = char;
span.classList.add('char');
const x = Math.random() * (Math.random() > 0.5 ? 300 : -300);
const y = Math.random() * (Math.random() > 0.5 ? 300 : -300);
span.style.cssText += `
color: #${Math.random().toString(16).substring(2,8)};
--x: ${x}px;
--y: ${y}px;
--delay: ${Math.random() * 0.5}s;
`;
frg.appendChild(span);
});
targetElm.appendChild(frg);
curkey ++;
setTimeout(() =>isSeeking = false, time);
}
</script>
</div>
<script type="module">
import linenumber from 'https://638183.freep.cn/638183/web/js/linenumber.js';
linenumber();
</script> 这里的 lrc2HC() 函数(行62~75)将原生lrc歌词转为早期的花潮lrc数组格式,得到的结果类似酱紫:
[ , ]
然后就处理这些数组,实现歌词同步。不过函数未处理原生复合歌词,若有,需要手动拆开为多行。
这里的歌词同步方式是新尝试:将歌词文本逐个封装在 span 标签里,给予每一个不同的文本色,出场时运行关键帧动画 fadeIn,从四面八方入框(坑)。此为 showLrc() 函数,行 91~113 便是。
代码无任何第三方依赖,完全自给自足,在此基础上可以考虑完善和扩展。 如果需要竖排,仅需将第 19 行CSS代码的 display 属性值 改为 block 代码于昨晚匆忙写就,其中 lrc2HC() 等函数的代码是以前写过的代码 这里好厉害👍🏻
有特色的showLrc
评分后代码就全挤在一起了 感谢老师精彩分享{:4_187:} 也曾年轻 发表于 2025-12-3 10:53
有特色的showLrc
评分后代码就全挤在一起了
刷新一下。这个目前找不到办法处理:论坛的局部刷新机制对 JS 的新声明关键字 const、let 以及对ES6不支持继承 清茶煮雪 发表于 2025-12-3 11:24
感谢老师精彩分享
{:4_190:} 亚伦影音工作室 发表于 2025-12-3 10:50
这里好厉害👍🏻
{:4_190:} 原生lrc歌词同步,逐字变色、逐字运动
代码无任何第三方依赖,既有复用性,还有扩展性。
辛苦了!马老师威武~{:4_176:}
这个太厉害了,逐字变色和有不同的动态方式入坑,让歌词太好看了{:4_199:} 这个让歌词很奇幻,其实前面的逐字高亮也是特色,也喜欢前面的{:4_187:}
这个不会逐字高亮了呢。 黑黑总能带来惊喜,厉害的{:4_199:} 红影 发表于 2025-12-3 18:23
黑黑总能带来惊喜,厉害的
哪里哪里 红影 发表于 2025-12-3 18:22
这个让歌词很奇幻,其实前面的逐字高亮也是特色,也喜欢前面的
这个不会逐字高亮了呢。
这个采用了另一种同步方式,不是模拟逐字高亮 红影 发表于 2025-12-3 18:20
这个太厉害了,逐字变色和有不同的动态方式入坑,让歌词太好看了
有点创意吧 杨帆 发表于 2025-12-3 14:51
原生lrc歌词同步,逐字变色、逐字运动
代码无任何第三方依赖,既有复用性,还有扩展性。
{:4_191:} 这个是创新了{:4_199:}{:4_199:} 小辣椒 发表于 2025-12-3 22:40
这个是创新了
{:4_190:}
页:
[1]