云中月圆(台语歌曲)(感谢亚伦的源码)
<style>@import url("https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&display=swap");#bj {
position: relative;
width: 1186px;
height: 680px;
margin-left: -300px;
margin-top: 10px;
overflow: hidden;
background:#000 url("https://picasa.eu.org/i/2026/05/31/dfgsxx.jpg")no-repeat;
background-size: cover;font-family: "Ma Shan Zheng","仿宋体","SimHei", "Arial", "sans-serif"
}
#background{z-index: 1;
width: 100%; height: 100%;
background: url("https://picasa.eu.org/i/2026/05/31/dugmea.jpg")no-repeat;
position: absolute;
top: 0px;
left: 0px;
animation: c 8s linear infinite;
background-size: cover;
}
@keyframes c {
from{transform: scale(1) ;filter: hue-rotate(0deg);
}
50%{transform: scale(4);
}
100%{transform: scale(4);opacity: 0;
}
}
.lyrics{margin: 0;z-index: 20;
top: 69%;display: none;
left: 50%;
transform: translate(-50%, -50%);
height: 100px; /* 调整高度,只容纳当前歌词 */
text-align: center;
position: absolute;animation:sese 1s infinite alternate;
}
.lyric-line{
width: 100%;
position: relative;
height: 60px;
overflow: visible;
font: 400 40px "Ma Shan Zheng","仿宋体","SimHei", "Arial", "sans-serif";
line-height: 60px;
text-align: left;
white-space: nowrap; /* 禁止换行 */
filter: drop-shadow(#fff 1px 0 0) drop-shadow(#fff 0 1px 0) drop-shadow(#fff -1px 0 0) drop-shadow(#fff 0 -1px 0);
}
.lyric-mask {
position: absolute;
top: 0;
left: 0;
width: 0;
overflow: hidden;
color: #ff0000;
height: 100%;
white-space: nowrap;
}
.lyric-original {
color: #00aa00;
white-space: nowrap;
}
#wrapper {z-index: 9;
position: absolute; writing-mode: vertical-lr;white-space: pre; width: 60px;height: 90%;top: 50px; left: 88%;
padding: 0px;
font:normal 2.6em "Ma Shan Zheng","仿宋体","SimHei", "Arial", "sans-serif";
filter: drop-shadow(#fff 1px 0 0) drop-shadow(#fff 0 1px 0) drop-shadow(#fff -1px 0 0) drop-shadow(#fff 0 -1px 0);
}
.char {
display: inline-block;
padding: 2px 2px;
opacity: 0;
transform: translate(var(--x), var(--y));
animation: fadeIn 1.5s var(--delay) forwards, sese 1s infinite alternate;
}
@keyframes fadeIn {
to {
transform:scale(1);
opacity: 1;
}
}
@keyframes flash {
to { filter: hue-rotate(360deg)brightness(100%); }
}
.lrc { z-index: 21; position: absolute; top: 20%; left: 41%; width: 740px; height: 350px; overflow: hidden; opacity: 0;}
.lrc #ul { width: 100%; padding: 0; list-style: none; transition: 0.3s all ease; margin: 0; }
.lrc #ul li { color: #fff; font: 300 20px 'YouYuan', sans-serif; transition: .3s all ease; list-style-type: none; text-align: center; display: block; padding: 0 10px; height: 50px; line-height: 50px; margin: 0 auto; cursor: pointer; }
.lrc #ul li.active { transform: scale(1.2); color: #FF0000; font-weight: 650; }
#s,#dh, #d, #g,#fullscreen{border-radius: 4px;position: relative;
color:#fff;background:#0000;box-shadow:0px 0px 0px 1px #fff;
padding: 4px 8px;z-index: 120;
font-size: 12px;
border: none;
cursor: pointer;top: 50px;left: 3%;
}
#bfq{
position:absolute;
width: 350px;
height:350px;overflow: hidden;
background: url('https://pic1.imgdb.cn/item/69ae5a3fafde4f1fb1c6982e.png') no-repeat center/100%;
transform:scale(.28);top: 66%; box-shadow: 0px 0px 0px 2px #cccccc, 0px 0px 0px 8px #000;
left: -120px;z-index: 20;}
#cp{
position:absolute;
width: 245px;border-radius: 50%;
height:245px;animation: rotating 6s infinite linear;
top:19%;background:repeating-radial-gradient(black, black 5px, #1C1C1C 6px, #1C1C1C 7px);
cursor: pointer;
left: 11%;z-index: 1;box-shadow:0px 0px 0px 1px #fff,0px 0px 0px 0px #880000;}
@keyframes rotating { to { transform: rotate(360deg); } }
.overlay {
content: '';
left: 50%;
top: 50%; transform: translate(-50%, -50%);
position: absolute;
width: 238px;
height: 238px;
background: linear-gradient(45deg, transparent, 40%, rgba(255,255,255,0.25), 60%, transparent);
border-radius: 50%;
}
.inner {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
box-shadow:0px 0px 0px 1px #eee,0px 0px 0px 2px #444;
background:#880000 url('') no-repeat center / cover;
border-radius: 50%;
}
.inner::before {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 15px;
height: 15px;
background: #ccc;
border-radius: 50%;
}
#cz {position: absolute;
top:-3%; left:50%;z-index: 2;
width: 150px;background: url('https://pic1.imgdb.cn/item/6688e0dad9c307b7e9a7a3e1.png')no-repeat center/85%;
height: 300px;
cursor: pointer;
}
.pink { transform:rotate(0deg);transform-origin: 100% 0%;}
.purple {transform-origin: 80% 0%;margin: 0px -25px;transform:rotate(-20deg);}
#biao{
position:absolute;background:#800000 url('https://pic1.imgdb.cn/item/69ac017f3dbab1ba32d7193b.png') no-repeat center/100% 100%;width:620px;height: 350px;border-radius:2%;transform:scale(0.2);
top: 62%; left: 25%;box-shadow: 0px 0px 0px 2px #cccccc, 0px 0px 0px 8px #000;
animation:sese 6sinfinite alternate;z-index: 20;
}
#zhen{position: absolute; transform: translate(-50%, -50%);
background:#ff0000;width:4px;height: 185px;border-radius:0% 0% 50% 50%;
transform-origin:center 0%;top: 270px; left: 50%;
animation:swin 0.4s ease-in-out infinite alternate;
}
#zhe{position: absolute; transform: translate(-50%, -50%);
background:#ff0000;width:4px;height: 185px;display: none;border-radius:0% 0% 50% 50%;
transform-origin:center 0%;top: 270px; left: 50%;
animation:swsw 1s ease-in-out infinite alternate;
}
#dian { width: 20px;height: 20px; background: #fff;top: 270px; left: 50%;position: absolute;
border-radius:50%;transform: translate(-50%, -50%);
}
@keyframes swin{
100%{
transform:rotate(-180deg);
}
60%{
transform:rotate(-160deg);
}
40%{
transform:rotate(-170deg);
}
0%{
transform:rotate(-140deg);
}
}
@keyframes swsw{
0%{
transform:rotate(-235deg);
}
100%{
transform:rotate(-235deg);
}
}
@keyframes sese{
0%{filter:hue-rotate(360deg)contrast(110%)brightness(90%);
}
}
#ba{
position: absolute;background: url('https://pic1.imgdb.cn/item/69ae5f7dafde4f1fb1c698f3.png') no-repeat center/100%;width:200px;height: 200px;border-radius:2%;transform:scale(0.5);box-shadow: 0px 0px 0px 2px #cccccc, 0px 0px 0px 4px #000;
top: 77%; right: -4%;z-index: 20;
}
#laba{position: absolute; transform: translatex(-50%);
background:url('https://pic1.imgdb.cn/item/69abf5b03dbab1ba32d6bd4d.png') no-repeat 0px 0px/100% 100%;width:150px;height: 150px;
top: 26px; left: 23px;text-align: center;cursor: pointer;
animation:sin 0.6sinfinite alternate;
}
@keyframes sin{
100%{
transform:scale(1);
}
40%{
transform:scale(1.02);
}
0%{
transform:scale(1);
}
}
#playbtn{margin: 0 120px ;top: 94.5%;width: 30px; height: 30px;position: absolute;cursor: pointer; z-index: 90;}
#cndpt{position: absolute; width: 80%; height:80%;
background:#fff;
clip-path: polygon(0% 0%, 0% 100%, 25% 100%, 25% 0, 50% 0, 50% 100%, 75% 100%, 75% 0);}
#enopg{ position: absolute;width: 80%; height: 80%;
opacity:0; background:#fff;
clip-path: polygon(75% 50%, 0 0, 0 100%)
}
#prog {position:absolute;
width: 68%;
height: 6px;background:#fff;
cursor: pointer;
bottom: 3%;border-radius: 2px;
left:13%;z-index: 190;}
#prog-bar {border-radius: 2px;
height: 100%;
background: #880000;
width: 0%;
}
#tmsg {position:absolute;
font: 600 14px sans-serif;
color: #fff;
bottom: 2%;
right: 10%;z-index: 90;}
</style>
<div id="bj">
<div class="s" id="background"></div>
<div id="bfq">
<div id="cz"class="pink"></div>
<div id="cp"><div class="inner"></div> <div class="overlay"></div></div>
</div>
<div id="biao">
<div id="zhen"></div>
<div id="zhe"></div>
<div id="dian"></div>
</div>
<div id="ba">
<div id="laba"></div>
</div>
<div id="wrapper">云中月圆</div>
<div class="lyrics" >
<div class="lyric-line">
<div class="lyric-mask"></div>
<div class="lyric-original"></div>
</div>
</div>
<div class="lrc">
<ul id="ul"></ul>
</div>
<div>
<span id="g" title="横/竖歌词模式">横排歌词</span>
<span id="d" onclick="btn()" title="多行歌词模式">多行歌词</span>
<span id="dh" onclick="btndh()" title="动画">动画变色</span>
<span id="s" onclick="btns()" title="动画">动画复原</span>
<span id="fullscreen" title="屏展模式">全屏欣赏</span>
</div>
<div id="playbtn" title="暂停">
<div id="cndpt"title="暂停"></div>
<div id="enopg" title="播放"></div>
</div>
<div id="prog" title="播放进度条"><div id="prog-bar"></div></div>
<div id="tmsg"></div>
</div>
<audio id="aud" src="https://tc.boxue.ltd/view.php/ab5664be6b4fca9e7ceacdf3a7bf384b.mp3" loop autoplay></audio>
<script>
const lrc = `云中月圆
天星伴相随
这首情歌
我要送乎你
无论你治叨位
海角天边
陇是代表我的心意
春风微微
花蕊送香味
这首情歌
我要送乎你
不管石头会烂
海水会干
阮也永远深深爱你
虽然世情多变化
我也将你放阮心肝
人生旅途亲像梦一摊
情歌永远有人听
海风海涌了解阮心声
情海浮沉的生命
我像孤单的船只
心爱的你甘知影
云中月圆
天星伴相随
这首情歌
我要送乎你
无论你治叨位
海角天边
陇是代表我的心意
春风微微
花蕊送香味
这首情歌
我要送乎你
不管石头会烂
海水会干
阮也永远深深爱你
虽然世情多变化
我也将你放阮心肝
人生旅途亲像梦一摊
情歌永远有人听
海风海涌了解阮心声
情海浮沉的生命
我像孤单的船只
心爱的你甘知影
虽然世情多变化
我也将你放阮心肝
人生旅途亲像梦一摊
情歌永远有人听
海风海涌了解阮心声
情海浮沉的生命
我像孤单的船只
心爱的你甘知影
`;
const aud= document.getElementById('aud');
const lyrics = parseLyrics(lrc);
const lyricMask = document.querySelector('.lyric-mask');
const lyricOriginal = document.querySelector('.lyric-original');
let currentIndex = -1;
let currentLyric = null;
// 解析歌词(支持两种格式)
function parseLyrics(lrcText) {
const lyrics = [];
if (lrcText.includes('karaoke.add')) {
const lineRegex = /karaoke\.add\('([^']+)', '([^']+)', '([^']+)', '([^']+)'\);/g;
let match;
while ((match = lineRegex.exec(lrcText)) !== null) {
const startTime = timeToMs(match);
const endTime = timeToMs(match);
const text = match.replace(/\[|\]/g, '').trim();
const durations = match.split(',').map(Number);
if (text) {
lyrics.push({startTime, endTime, text, durations});
}
}
}
else if (lrcText.includes('[')) {
const lines = lrcText.split('\n').filter(line => line.trim());
lines.forEach((line, index) => {
const timeMatch = line.match(/\[(\d+:\d+\.\d+)\]/);
if (timeMatch) {
const timeStr = timeMatch;
const text = line.replace(/\[.*?\]/, '').trim();
if (text) {
const startTime = timeToMs(timeStr);
const nextLine = lines;
const nextTimeMatch = nextLine ? nextLine.match(/\[(\d+:\d+\.\d+)\]/) : null;
const endTime = nextTimeMatch ? timeToMs(nextTimeMatch) : startTime + 5000;
lyrics.push({
startTime,
endTime,
text,
durations: calculateCharDurations(text, startTime, endTime)
});
}
}
});
}
return lyrics;
}
function calculateCharDurations(text, startTime, endTime) {
const totalDuration = endTime - startTime;
const charCount = text.length;
const baseDur = Math.floor(totalDuration / charCount);
const durations = new Array(charCount).fill(baseDur);
const remainder = totalDuration % charCount;
for (let i = 0; i < remainder; i++) {
durations++;
}
return durations;
}
function timeToMs(timeStr) {
const parts = timeStr.split(':');
const minutes = parseInt(parts, 10);
const secondsAndMs = parts.split('.');
const seconds = parseInt(secondsAndMs, 10);
const ms = parseInt(secondsAndMs || 0, 10);
return minutes * 60 * 1000 + seconds * 1000 + ms;
}
function getCurrentLyricIndex(lyrics, currentTimeMs) {
for (let i = 0; i < lyrics.length; i++) {
if (currentTimeMs >= lyrics.startTime && currentTimeMs <= lyrics.endTime) {
return i;
}
}
return -1;
}
function updateLyricDisplay(index) {
if (index < 0 || index >= lyrics.length) return;
currentIndex = index;
currentLyric = lyrics;
lyricOriginal.textContent = currentLyric.text;
lyricMask.textContent = currentLyric.text;
lyricMask.style.width = '0%';
}
function updateLyricMask(currentTimeMs) {
if (!currentLyric) return;
const lyricStartTime = currentLyric.startTime;
const elapsed = currentTimeMs - lyricStartTime;
const totalDuration = currentLyric.durations.reduce((sum, d) => sum + d, 0);
let charIndex = 0;
let accumulatedTime = 0;
for (let i = 0; i < currentLyric.durations.length; i++) {
accumulatedTime += currentLyric.durations;
if (elapsed <= accumulatedTime) {
charIndex = i + 1;
break;
}
}
if (elapsed >= totalDuration) {
charIndex = currentLyric.text.length;
}
charIndex = Math.min(charIndex, currentLyric.text.length);
const tempSpan = document.createElement('span');
tempSpan.style.visibility = 'hidden';
tempSpan.style.position = 'absolute';
tempSpan.style.fontSize = '50px';
tempSpan.style.fontWeight = '300';
document.body.appendChild(tempSpan);
const visibleText = currentLyric.text.substring(0, charIndex);
tempSpan.textContent = visibleText;
const width = tempSpan.offsetWidth;
document.body.removeChild(tempSpan);
lyricMask.style.width = `${width}px`;
}
// 监听更新歌词
aud.addEventListener('timeupdate', () => {
const currentTimeMs = aud.currentTime * 1000;
const index = getCurrentLyricIndex(lyrics, currentTimeMs);
if (index !== currentIndex) {
updateLyricDisplay(index);
}
updateLyricMask(currentTimeMs);
});
updateLyricDisplay(0);
const gcAr = lrc2HC(lrc);
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 ? 600 : -300);
const y = Math.random() * (Math.random() > 0.5 ? 600 : -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>
<script>
let lrcArr = lrc.split('\n');
let result = [];
var audio = document.querySelector("#aud");
var ul = document.querySelector("#ul");
var container = document.querySelector(".lrc");
for (let i = 0; i < lrcArr.length; i++) {
var lrcData = lrcArr.split(']');
if (lrcData.length < 2) continue;
var lrcTime = lrcData.substring(1);
var obj = {
time: parseTime(lrcTime),
word: lrcData.trim()
}
result.push(obj);
}
function parseTime(lrcTime) {
let lrcTimeArr = lrcTime.split(":");
return +lrcTimeArr * 60 + parseFloat(lrcTimeArr);
}
function getIndex() {
let time = audio.currentTime;
for (let i = 0; i < result.length; i++) {
if (result.time > time) {
return i - 1;
}
}
return result.length - 1;
}
function createElements() {
let fragment = document.createDocumentFragment();
for (let i = 0; i < result.length; i++) {
let li = document.createElement("li");
li.innerText = result.word;
li.addEventListener("click", function () {
audio.currentTime = result.time;
setOffset();
});
fragment.appendChild(li);
}
ul.appendChild(fragment);
}
createElements();
let containerHeight = container.clientHeight;
let liHeight = ul.children?.clientHeight || 50;
let minOffset = 0;
let maxOffset = ul.clientHeight - containerHeight;
function setOffset() {
const index = getIndex();
if (index < 0) return;
const liHeight = ul.children?.clientHeight || 50;
let offset = liHeight * index - containerHeight / 2 + liHeight / 2;
offset = Math.max(minOffset, Math.min(offset, maxOffset));
ul.style.transform = `translateY(${-offset}px)`;
ul.querySelectorAll('.active').forEach(li => li.classList.remove('active'));
if (index < ul.children.length) {
ul.children.classList.add('active');
}
}
audio.addEventListener("timeupdate", setOffset);
</script>
<script>
var g1=document.getElementById("wrapper");
var dh=document.getElementById("background");
const g2 = document.querySelector('.lyrics');
const d = document.querySelector('.lrc');
const s = document.querySelector('.s');
functionbtn(){
d.style.opacity= '1';
g1.style.display = 'none';
g2.style.display = 'none';
};
functionbtndh(){
dh.style.filter= 'hue-rotate(360deg)';
dh.style.animation= 'c 6s linear infinite';
};
functionbtns(){
s.style.filter= 'hue-rotate(0deg)';
s.style.animation= 'c 6s linear infinite';
};
let fss = true;
g.onclick = () => {
if (fss) {g.innerText = '竖排歌词';
g1.style.display = 'none';
g2.style.display = 'block';
d.style.opacity= '0';
}else {g.innerText = '横排歌词';
g1.style.display = 'block';
g2.style.display = 'none';
d.style.opacity= '0';
}
fss = !fss;
};
let fs = true;
fullscreen.onclick = () => {
if (fs) {
fullscreen.innerText = '退出全屏';
bj.requestFullscreen();
} else {
fullscreen.innerText = '全屏欣赏';
document.exitFullscreen();
}
fs = !fs;
};
prog.onclick = (e) => { aud.currentTime = aud.duration * e.offsetX / prog.offsetWidth;}
var progBar = document.getElementById('prog-bar');
aud.addEventListener('timeupdate', () => {
varpercent= (aud.currentTime / aud.duration) * 100;
progBar.style.width = percent + '%';
});
aud.addEventListener('timeupdate', () => {
tmsg.innerText = toMin(aud.currentTime) + ' | ' + toMin(aud.duration);});
let toMin = (val) => {
if (!val) return '00:00';
val = Math.floor(val);
let min = parseInt(val / 60),
sec = parseFloat(val % 60);
if (min < 10) min = '0' + min;
if (sec < 10) sec = '0' + sec;
return min + ':' + sec;
};
playbtn.onclick=() => aud.paused ? (aud.play(),enopg.style.opacity= '0',cndpt.style.opacity = '1',background.style.animationPlayState = 'running', cz.classList.remove('purple'),intro.style.animationPlayState = 'running') : (aud.pause(),enopg.style.opacity = '1',cndpt.style.opacity = '0',background.style.animationPlayState = 'paused',cz.classList.add('purple'),intro.style.animationPlayState = 'paused');
playbtn.style.animationPlayState = aud.paused ? 'paused': 'running';
let mState = () => aud.paused ? (zhen.style.display= 'none',zhe.style.display= 'block') : (zhen.style.display= 'block',zhe.style.display= 'none');
aud.addEventListener('play', () => mState());
aud.addEventListener('pause', () => mState());
const intro= document.querySelector('.intro');
laba.style.animationPlayState=cp.style.animationPlayState =aud.paused ? 'paused' : 'running';
aud.addEventListener('playing', () =>laba.style.animationPlayState=cp.style.animationPlayState= 'running');
aud.addEventListener('pause', () =>laba.style.animationPlayState=cp.style.animationPlayState= 'paused');
</script>
好像评不了分 欣赏高老师带来的精彩音画。 这些按钮都很好用,亚伦老师的代码好,高老师的制作也很好。
不过代码好像还是有点小问题,评分无法选择分数,还有代码导致表情出不来。 这首台语歌曲很好听,还是第一次听到呢。
台语好像和闽南话很像呢。 方言歌曲挺好听,当然我听不懂, 效果漂亮,谢谢精彩分享
页:
[1]