听风听雨听见你
<!DOCTYPE html><html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<title>方羿 - 听风听雨听见你</title>
<link href="https://fonts.googleapis.com/css2?family=Liu+Jian+Mao+Cao&family=Long+Cang&family=Ma+Shan+Zheng&family=ZCOOL+KuaiLe&family=ZCOOL+QingKe+HuangYou&display=swap" rel="stylesheet">
<link rel="preload" href="https://bbs.cnzv.cc/up/upload/pic/3374f313d13a179738c09a52607a7f9b.jpg" as="image">
<style>
#papa{position:relative;display:grid;place-items:center;margin:30px 0;width:1280px;height:750px;left:calc(50% - 81px);transform:translateX(-50%);box-shadow:3px 3px 6px gray;overflow:hidden;z-index:1;background:var(--bg1);--bg1:#000 url('https://bbs.cnzv.cc/up/upload/pic/783bf43278c17b5f56b9554758bd4e14.jpg') no-repeat 50% 25%/cover;--bg2:#000 url('https://bbs.cnzv.cc/up/upload/pic/3374f313d13a179738c09a52607a7f9b.jpg') no-repeat 50% 25%/cover;font-family:"ZCOOL KuaiLe","Ma Shan Zheng","Long Cang","华文行楷","SimHei","Arial","sans-serif";--state:running;}
#LRCShow{position:absolute;top:10%;left:50%;transform:translate(-50%,calc(-50% - 20px));width:70%;height:180px;z-index:3;display:flex;align-items:center;justify-content:center;filter:drop-shadow(0 4px 25px rgba(0,20,30,0.7));pointer-events:none;}
.lyricDisp{position:relative;font:58px/1.5 'Long Cang','ZCOOL KuaiLe','Ma Shan Zheng','Microsoft YaHei','华文隶书','KaiTi',cursive;font-weight:400;white-space:nowrap;transition:0.2s;width:fit-content;max-width:100%;transform-origin:center center;animation:yaoSoft 1.6s ease-in-out infinite alternate;margin:0;letter-spacing:4px;color:transparent;-webkit-text-stroke:0.8px rgba(255,255,255,0.35);text-stroke:0.8px rgba(255,255,255,0.35);text-align:center;}
.lyricDisp.paused{animation-play-state:paused !important;}
@keyframes yaoSoft{0%{transform:perspective(600px) rotateX(-10deg) rotateY(10deg) scale(1.05) translateY(-3px);}100%{transform:perspective(600px) rotateX(10deg) rotateY(-10deg) scale(0.95) translateY(3px);}}
.lyricDisp::before{position:absolute;content:attr(data-lrc);width:0;height:100%;left:0;top:0;color:transparent;background:linear-gradient(90deg,#FF6B6B 15%,#FFD93D 30%,#6BCB77 45%,#4D96FF 60%,#9B59B6 75%,#FF6B6B 90%);-webkit-background-clip:text;background-clip:text;overflow:hidden;white-space:nowrap;animation:var(--aniName) var(--durTime) linear forwards;animation-play-state:var(--aniPlayState);pointer-events:none;-webkit-text-stroke:0.8px rgba(255,255,255,0.35);text-stroke:0.8px rgba(255,255,255,0.35);}
.lyricDisp.paused::before{animation-play-state:paused !important;}
@keyframes bgMove1{from{width:0;}to{width:100%;}}
@keyframes bgMove0{from{width:0;}to{width:100%;}}
.prog{position:absolute;left:30px;bottom:30px;width:300px;height:2px;background:rgba(255,255,255,0.3);cursor:pointer;z-index:20;--prog:0%;border-radius:2px;}
.prog .fill{position:absolute;left:0;top:0;height:100%;width:var(--prog);background:linear-gradient(90deg,#6BCB77,#4D96FF);border-radius:2px;box-shadow:0 0 15px rgba(75,200,120,0.3);transition:width 0.08s linear;}
.prog .time-display{position:absolute;bottom:12px;left:50%;transform:translateX(-50%);font-size:18px;font-family:'Consolas',monospace;color:rgba(255,255,255,0.55);letter-spacing:1px;white-space:nowrap;text-shadow:0 0 10px rgba(0,0,0,0.8);}
#playBtnImg{position:absolute;right:35px;bottom:32px;width:95px;height:95px;border-radius:50%;cursor:pointer;box-shadow:0 0 20px rgba(255,200,200,0.2);border:2px solid rgba(255,255,255,0.25);transition:transform 0.2s,border-color 0.2s;z-index:20;animation:rotate 8s linear infinite var(--state);pointer-events:auto;}
#playBtnImg:hover{transform:scale(1.08);border-color:rgba(255,215,0,0.4);}
#playBtnImg:active{transform:scale(0.92);}
#lrcContent0{display:none;}
.pd-vid{position:absolute;width:100%;height:100%;object-fit:cover;mask:linear-gradient(45deg,red 88%,transparent 90%);-webkit-mask:linear-gradient(45deg,red 88%,transparent 90%);mix-blend-mode:screen;z-index:1;pointer-events:none;}
#canvas{position:relative;top:15%;left:-45%;transform:translateX(45%);cursor:pointer;}
@media (max-width:1300px){#playerCore{width:96vw;height:90vh;border-radius:16px;}.lyricDisp{font-size:32px;}#LRCShow{width:75%;height:150px;}}
@media (max-width:820px){.lyricDisp{font-size:26px;letter-spacing:2px;}#LRCShow{width:80%;height:130px;}}
@media (max-width:480px){.lyricDisp{font-size:18px;letter-spacing:1px;}#LRCShow{width:85%;height:100px;}}
#fullscreen{border-radius:4px;position:absolute;color:DarkGray;padding:4px 8px;z-index:12;font-size:25px;border:none;cursor:pointer;top:25px;left:25px;background:transparent;}
#fullscreen:hover{font-style:italic;}
.myCanvas{position:absolute;z-index:5;left:calc(50% + 80px);transform:translateX(-50%);bottom:-130px;animation:scale 12s ease infinite alternate var(--state);}
@keyframes scale{0%{transform:translateX(-50%) perspective(800px) rotateY(0deg) scale(0.01);}20%{transform:translateX(-50%) perspective(800px) rotateY(0deg) scale(1);}40%{transform:translateX(-50%) perspective(800px) rotateY(-25deg) scale(1.2);}60%{transform:translateX(-50%) perspective(800px) rotateY(25deg) scale(1.2);}80%{transform:translateX(-50%) perspective(800px) rotateY(0deg) scale(1);}100%{transform:translateX(-50%) perspective(800px) rotateY(0deg) scale(0.01);}}
@keyframes rotate{from{transform:rotate(0);}to{transform:rotate(360deg);}}
</style>
</head>
<body>
<div id="papa">
<canvas class="myCanvas" width="800" height="400"></canvas>
<canvas id="canvas" width="300" height="300"></canvas>
<div id="fullscreen">全屏欣赏</div>
<video class="pd-vid" src="https://img2.tukuppt.com/video_show/15653652/00/80/83/60d04564c32f7.mp4" autoplay loop muted></video>
<div id="LRCShow"></div>
<div class="prog" id="prog">
<div class="fill" id="progFill"></div>
<div class="time-display" id="timeDisplay">00:00 / 00:00</div>
</div>
<img id="playBtnImg" src="https://s41.ax1x.com/2026/07/08/pmriFQ1.png" alt=" " />
<textarea id='lrcContent0'></textarea>
</div>
<script>
var songData = {
title: '听风听雨听见你',
audio: 'http://music.163.com/song/media/outer/url?id=3366923729.mp3',
lrc: `听风听雨听见你
演唱:方羿
如果思念是风
我愿随风飘向你的天空
如果思念是雨
我愿随雨落在你的心中
风能带去我的想念
雨能带去我的爱恋
我就是风我就是雨
风风雨雨把你思念
让思念的风吹啊吹
吹到你所在的地方
让爱情的雨落啊落
落进你温柔的心房
风中有我无尽的思念
雨里有我深情的诺言
无论天涯海角有多远
我对你的思念永不变
风也思念雨也思念
你是我永远的挂牵
风也思念雨也思念
我的爱永远在你心间
当春风吹绿了枝头
当夏雨滋润了眼眸
当秋叶染红了路口
当冬雪覆盖了街头
这份爱始终如旧
让思念的风吹啊吹
吹到你所在的地方
让爱情的雨落啊落
落进你温柔的心房
风中有我无尽的思念
雨里有我深情的诺言
无论天涯海角有多远
我对你的思念永不变
我对你的思念永不变
`
};
var lrcPlayer = function() {
return this.init.apply(this, arguments);
};
lrcPlayer.prototype = {
constructor: lrcPlayer,
init: function(opts) {
this.lyricTxtObj = document.getElementById(opts.lrcTxtID);
var lyricTxt = this.lyricTxtObj.value;
this.showLrcObj = document.getElementById(opts.lrcShowID);
this.showLrcObj.innerHTML = '';
this.gcline = document.createElement('div');
this.gcline.className = 'lyricDisp';
this.showLrcObj.appendChild(this.gcline);
this.audioCtrl = document.getElementById(opts.audioCtrl);
this.progressInfo = document.getElementById('timeDisplay');
this.lrcVec = this.parseLrc(lyricTxt);
console.log('歌词条目总数:', this.lrcVec.length);
this.genPlayer(opts.audioURL);
this.isPlaying = false;
return this;
},
parseLrc: function(lyricTxt) {
var lines = lyricTxt.split('\n');
var result = [];
for (var i = 0; i < lines.length; i++) {
var line = lines;
var timeMatch = line.match(/^\[(\d{2}):(\d{2})\.(\d{2})\]/);
if (timeMatch) {
var minutes = parseInt(timeMatch);
var seconds = parseInt(timeMatch);
var milliseconds = parseInt(timeMatch);
var time = minutes * 60 + seconds + milliseconds / 100;
var text = line.replace(timeMatch, '').trim();
if (text) result.push({ time: time, text: text });
}
}
result.sort(function(a, b) { return a.time - b.time; });
return result;
},
resetLyrics: function() {
this.idx = 0;
if (this.lrcVec && this.lrcVec.length > 0) {
var text = this.lrcVec.text || ' ';
this.gcline.innerHTML = text;
this.gcline.setAttribute('data-lrc', text);
this.gcline.style.setProperty('--aniName', 'bgMove0');
this.gcline.style.setProperty('--durTime', '2000ms');
this.gcline.style.setProperty('--aniPlayState', 'running');
}
},
showLrc: function(durTime) {
if (this.idx >= this.lrcVec.length) return;
var text = this.lrcVec.text;
if (text.length === 0) text = ' ';
this.gcline.innerHTML = text;
this.gcline.setAttribute('data-lrc', text);
this.gcline.style.setProperty('--aniName', 'bgMove' + (this.idx % 2));
var finalDur = Math.max(durTime * 0.7, 600);
finalDur = Math.min(finalDur, 3000);
this.gcline.style.setProperty('--durTime', finalDur + 'ms');
this.gcline.style.setProperty('--aniPlayState', 'running');
},
genPlayer: function(mUrl) {
var that = this;
this.mObj = document.createElement("audio");
this.mObj.loop = true;
this.mObj.muted = false;
this.mObj.src = mUrl;
this.showLrcObj.appendChild(this.mObj);
this.idx = 0;
this.mObj.addEventListener('loadedmetadata', function() {
if (that.lrcVec.length > 0) {
var text = that.lrcVec.text || ' ';
that.gcline.innerHTML = text;
that.gcline.setAttribute('data-lrc', text);
that.gcline.style.setProperty('--aniName', 'bgMove0');
that.gcline.style.setProperty('--durTime', '2000ms');
that.gcline.style.setProperty('--aniPlayState', 'running');
that.idx = 0;
}
});
this.mObj.addEventListener('ended', function() {
that.idx = 0;
that.isPlaying = false;
that.audioCtrl.classList.remove('playing');
that.gcline.style.setProperty('--aniPlayState', 'paused');
that.resetLyrics();
that.mObj.play().catch(function() {});
that.resetLyrics();
that.mObj.play().catch(function() {});
syncAllUIState();
});
var vid = document.querySelector('video');
const bg1 = getComputedStyle(papa).getPropertyValue('--bg1');
const bg2 = getComputedStyle(papa).getPropertyValue('--bg2');
this.mObj.addEventListener('playing', function() {
that.isPlaying = true;
if (vid && vid.paused) vid.play().catch(function() {});
papa.style.setProperty('--state', 'running');
papa.style.background = bg1;
that.audioCtrl.classList.add('playing');
that.gcline.style.setProperty('--aniPlayState', 'running');
if (this.currentTime < 0.5 && that.idx > 0) {
that.idx = 0;
that.resetLyrics();
}
that.gcline.classList.remove('paused');
syncAllUIState();
});
this.mObj.addEventListener('pause', function() {
that.isPlaying = false;
if (vid && !vid.paused) vid.pause();
papa.style.setProperty('--state', 'paused');
papa.style.background = bg2;
that.audioCtrl.classList.remove('playing');
that.gcline.style.setProperty('--aniPlayState', 'paused');
that.gcline.classList.add('paused');
syncAllUIState();
});
var lastUpdateTime = 0;
this.mObj.addEventListener('timeupdate', function() {
var now = Date.now();
if (now - lastUpdateTime < 100) return;
lastUpdateTime = now;
var current = this.currentTime || 0;
var duration = this.duration || 0;
if (duration > 0) {
var min = Math.floor(current / 60);
var sec = Math.floor(current % 60);
var min2 = Math.floor(duration / 60);
var sec2 = Math.floor(duration % 60);
that.progressInfo.textContent =
String(min).padStart(2, '0') + ':' + String(sec).padStart(2, '0') +
' / ' +
String(min2).padStart(2, '0') + ':' + String(sec2).padStart(2, '0');
var pct = (current / duration) * 100;
document.getElementById('progFill').style.width = Math.min(pct, 100) + '%';
document.getElementById('prog').style.setProperty('--prog', Math.min(pct, 100) + '%');
}
if (that.idx < that.lrcVec.length - 1) {
var nextTime = that.lrcVec.time;
if (this.currentTime >= nextTime - 0.2) {
that.idx++;
var dur = (that.lrcVec.time - that.lrcVec.time) * 950;
dur = Math.max(dur * 0.7, 600);
dur = Math.min(dur, 3000);
that.showLrc(dur);
}
}
});
this.audioCtrl.onclick = function(e) {
e.stopPropagation();
if (that.mObj.paused) {
that.mObj.play().catch(function(err) {
console.log('播放失败:', err);
});
} else {
that.mObj.pause();
}
};
var progEl = document.getElementById('prog');
progEl.addEventListener('click', function(e) {
e.stopPropagation();
var rect = this.getBoundingClientRect();
var ratio = (e.clientX - rect.left) / rect.width;
var target = Math.max(0, Math.min(1, ratio)) * that.mObj.duration;
if (!isNaN(target) && isFinite(target)) {
that.mObj.currentTime = target;
var idx = 0;
for (var i = 0; i < that.lrcVec.length; i++) {
if (target >= that.lrcVec.time) idx = i;
else break;
}
that.idx = idx;
if (that.lrcVec.length > 0 && that.idx < that.lrcVec.length) {
var text = that.lrcVec.text || ' ';
that.gcline.innerHTML = text;
that.gcline.setAttribute('data-lrc', text);
that.gcline.style.setProperty('--aniName', 'bgMove' + (that.idx % 2));
that.gcline.style.setProperty('--durTime', '1500ms');
that.gcline.style.setProperty('--aniPlayState', 'running');
}
syncAllUIState();
}
});
setTimeout(function() {
that.mObj.play().catch(function(err) {
console.log('自动播放被拦截,点击按钮播放:', err);
});
}, 500);
},
stopMusic: function() {
this.mObj.pause();
this.isPlaying = false;
this.audioCtrl.classList.remove('playing');
},
setAudioUrl: function(mUrl) {
this.mObj.src = mUrl;
},
reStart: function() {
this.idx = 0;
this.mObj.currentTime = 0;
this.mObj.play().catch(function() {});
},
isMusicEnd: function() {
return this.mObj.ended;
}
};
var opts = {
lrcTxtID: 'lrcContent0',
lrcShowID: "LRCShow",
audioURL: songData.audio,
audioCtrl: 'playBtnImg'
};
document.getElementById('lrcContent0').value = songData.lrc;
var player = new lrcPlayer(opts);
console.log('歌词同步模块加载完成,点击底部按钮播放');
const canvas1 = document.querySelector('.myCanvas');
const ctx = canvas1.getContext('2d');
ctx.save();
ctx.font = 'bold 66px 华文隶书,Microsoft YaHei';
ctx.strokeStyle = "rgb(0,191,255)";
ctx.lineWidth = 1;
ctx.textAlign = 'left';
ctx.strokeText("听风听雨听见你", 130,200);
ctx.restore();
const canvas = document.getElementById("canvas");
let angle = 0;
let animationId = null;
function syncAllUIState() {
const audio = player.mObj;
if (!audio) return;
playBtnImg.title = audio.paused ? "播放" : "暂停";
canvas.title = audio.paused ?"播放" : "暂停";
if (audio.paused) {
stopAnimation();
} else {
if (!animationId) draw();
}
}
function draw() {
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(angle);
ctx.scale(0.8,0.8);
for (let i = 0; i < 12; i++) {
ctx.save();
let hue = (360 / 12) * i;
ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
ctx.rotate(Math.PI * 2 / 12 * i);
ctx.fillRect(0, 0, 100, 2);
ctx.beginPath();
var radgrad2 = ctx.createRadialGradient(0, 105, 0, 0, 105, 10);
radgrad2.addColorStop(0.03, "red");
radgrad2.addColorStop(0.30, "lightgreen");
radgrad2.addColorStop(1, "darkred");
ctx.fillStyle = radgrad2;
ctx.arc(0, 110, 10, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
ctx.beginPath();
ctx.arc(0, 0, 10, 0, Math.PI * 2);
ctx.fillStyle = "rgba(248, 243, 235,0.8)";
ctx.fill();
ctx.restore();
angle -= 0.015;
animationId = requestAnimationFrame(draw);
}
function stopAnimation() {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
}
canvas.onclick = (e) => {
e.stopPropagation();
playBtnImg.click();
};
const fullscreen = document.getElementById('fullscreen');
let fs = true,fsTimer;
fullscreen.onclick = ()=>{
if(fs){
fullscreen.innerText = '退出全屏';
papa.requestFullscreen();
}else{
fullscreen.innerText = '全屏欣赏';
document.exitFullscreen();
}
fs = !fs;
};
papa.addEventListener('mousemove', () => {
clearTimeout(fsTimer);
fullscreen.style.opacity = '1';
fsTimer = setTimeout(() => fullscreen.style.opacity = '0', 2500);
});
document.addEventListener('visibilitychange', () => {
const audio = player.mObj;
if (!audio) return;
if (document.hidden) {
if (!audio.paused) audio.pause();
} else {
if (audio.paused && !audio.ended) audio.play().catch(() => {});
}
setTimeout(syncAllUIState, 50);
});
['contextmenu', 'dragstart', 'selectstart'].forEach(ev =>
papa.addEventListener(ev, (e) => { e.preventDefault(); })
);
playBtnImg.onanimationiteration = () => {
playBtnImg.style.setProperty('filter', `hue-rotate(${60 + Math.random() * 300}deg)`);
};
function init() {
draw();
setTimeout(syncAllUIState, 600);
}
init();
</script>
</body>
</html>
本帖最后由 杨帆 于 2026-7-9 18:37 编辑
代码来自马黑黑老师、了了子老师分享作品,在此表示感谢{:4_190:} 冷美人更有魅力。 两个小播都能暂停,暂停的时候背景图也变了呢。
飘动的歌词很漂亮,欣赏杨帆好帖{:4_187:} 梦油 发表于 2026-7-9 19:54
冷美人更有魅力。
呵呵,谢谢梦兄欣赏,祝夏安{:4_190:} 红影 发表于 2026-7-9 21:28
两个小播都能暂停,暂停的时候背景图也变了呢。
飘动的歌词很漂亮,欣赏杨帆好帖
鼓捣着玩呢,谢谢影子鼓励,祝夏安{:4_204:} 欣赏扬帆的好制作,别具一格,也是我很喜欢听的歌,赞佩!{:4_204:}{:4_190:}
音画效果惊艳,歌曲好听,歌词效果特别赞,这套组合代码一定化费了不少时间。
辛苦了!{:4_187:} 欣赏杨帆带来的精彩音画。祝夏安!{:4_204:}{:4_199:} 欣赏杨帆老师精彩作品! 霜染枫丹 发表于 2026-7-10 00:15
欣赏扬帆的好制作,别具一格,也是我很喜欢听的歌,赞佩!
谢谢喜欢,谢谢鼓励,祝枫丹老师夏安{:4_204:} 梦江南 发表于 2026-7-10 07:43
音画效果惊艳,歌曲好听,歌词效果特别赞,这套组合代码一定化费了不少时间。
辛苦了!
鼓捣着纯玩,谢谢江南喜欢与鼓励,祝夏安{:4_204:} 雨季工作室 发表于 2026-7-10 08:52
欣赏杨帆老师精彩作品!
谢谢雨季兄弟鼓励,祝夏安{:4_190:} 杨帆 发表于 2026-7-9 22:09
呵呵,谢谢梦兄欣赏,祝夏安
谢谢杨帆朋友的美好祝福。 杨帆这个制作漂亮,代码运用的非常好,小辣椒欣赏加学习{:4_187:} 小辣椒 发表于 2026-7-10 22:48
杨帆这个制作漂亮,代码运用的非常好,小辣椒欣赏加学习
问好小辣椒,谢谢鼓励,祝夏安{:4_187:} 杨帆 发表于 2026-7-9 22:11
鼓捣着玩呢,谢谢影子鼓励,祝夏安
制作很精美,给杨帆点赞{:4_187:}
页:
[1]