枫叶歌曲二首 TO:亚纶
<!DOCTYPE html><html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>音乐播放器</title>
<style>
@import url("https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&display=swap");
#bj {
position: relative;
width: 1300px;
height: 750px;
margin: 130px 0 20px calc(50% - 731px);
overflow: hidden;
z-index: 1;
background: #55aa55 url(https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/9F.gif ) no-repeat center/cover;
border-radius: 0px;
box-shadow: 0 15px 0px rgba(0, 0, 0, 0);
font-family: "Ma Shan Zheng","华文行楷","SimHei", "Arial", "sans-serif";
}
.song-info {
animation: flash 2s linear infinite;
position: absolute;
top: 20px;
left: 0;
width: 100%;
text-align: center;
z-index: 5;
padding: 10px;
}
.song-title {
font-size: 38px;
font-weight: 300;
color: #00ff00;
text-shadow: 0 0px 0px rgba( );
margin-bottom: 5px;
}
.song-artist {
font-size: 28px;
color: #00ff00;
}
canvas {
animation: flash 1s linear infinite;
position: absolute;
z-index: 2;
width: 120%;
height: 100%;
display: block;
cursor: pointer;
transition: transform 0.3s ease;
margin-top: -100px;
margin-left: -66px;
pointer-events: none;
}
canvas:hover {
transform: scale(1.05);
}
.lyric-preview {
display: none;
opacity: 1;
position: absolute;
top: 50px;
left: 50%;
transform: translateX(-50%);
color: #00ff00;
font-size: 16px;
text-align: center;
width: 70%;
z-index: 3;
cursor: pointer;
padding: 12px;
border-radius: 10px;
background: rgba(0, 0, 0, 0);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
@keyframes flash {
to { filter: hue-rotate(360deg)brightness(260%); }
}
.lyric-preview:hover {
display: none;
background: rgba(0, 0, 0, 0);
transform: translateX(-50%) scale(1.02);
}
.prev-lyric {
opacity: 1;
margin-bottom: 6px;
transition: opacity 0.2s ease;
color: #00ff00;
font-size: 14px;
}
.current-lyric {
font-size: 18px;
font-weight: bold;
color: #00ff00;
transition: opacity 0.2s ease;
}
.next-lyric {
opacity: 1;
margin-top: 6px;
transition: opacity 0.2s ease;
color: #00ff00;
font-size: 14px;
}
.lyric-preview:active .current-lyric {
opacity: 1;
}
/* 播放按钮样式 */
#player {
animation: flash 3s linear infinite;
position: absolute;
z-index: 10;
left: 5%;
bottom: 120px;
width: 120px;
height: 120px;
opacity: 1;
transition: .4s;
display: grid;
place-items: center;
cursor: pointer;
background: rgba(255, 255, 255, 0.);
border-radius: 50%;
box-shadow: 0 0px 0px rgba(0, 0, 0, 0.0);
}
#player::before {
position: absolute;
z-index: 1;
content: '';
width: 120px;
height: 120px;
background: url(https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/ann.png) no-repeat center/cover;
border-radius: 50%;
transition: transform 0.3s ease;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
#player.playing::before {
animation: rotate 5s linear infinite;
}
#player.playing:hover::before {
animation-duration: 5s;
}
#player:hover {
transform: scale(1.01);
background: rgba(255, 255, 255, 0);
}
#bgVideo {
position: absolute;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
filter: brightness(0.7);
object-fit: cover;
opacity: 1;
}
/* 进度条容器 */
.progress-container {
position: absolute;
bottom: 40px;
left: 32%;
width: 33%;
z-index: 10;
background: #444;
height: 6px;
border-radius: 3px;
cursor: pointer;
}
.progress-bar {
height: 100%;
width: 0%;
background:#cc9b97;
border-radius: 3px;
transition: width 0.1s linear;
position: relative;
}
.progress-bar::after {
content: '';
position: absolute;
right: -8px;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
background: #222;
border-radius: 50%;
box-shadow: 0 0 10px rgba(233, 69, 96, 0.8);
opacity: 0;
transition: opacity 0.2s;
}
.progress-container:hover .progress-bar::after {
opacity: 1;
}
.time-display {
display: flex;
justify-content: space-between;
margin-top: -24px;
font-size: 14px;
color: #222;
}
.controls {
position: absolute;
bottom: 70px;
right: 5%;
display: flex;
align-items: center;
gap: 15px;
z-index: 10;
}
.control-btn {
background:rgba(255, 255, 255, 0) ;
border: none;
color: #222;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
font-size: 12px;
}
.control-btn:hover {
background: rgba(255, 255, 255, 0);
transform: scale(1);
}
.volume-container {
display: flex;
align-items: center;
gap: 10px;
}
.volume-slider {
width: 0px;
height: 0px;
background: rgba(255, 255, 255, 0);
border-radius: 0px;
position: relative;
}
.volume-level {
height: 100%;
width: 80%;
background: #e94560;
border-radius: 2px;
}
/* 加载进度显示 */
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
color: #fff;
z-index: 20;
background: rgba(0, 0, 0, 0.7);
padding: 20px 40px;
border-radius: 10px;
display: none;
}
/* 播放列表样式 */
.playlist-container {
position: absolute;
top: 20px;
right: 30px;
z-index: 10;
width: 40px;
height: 40px;
transition: all 0.3s ease;
}
.playlist-trigger {
width: 40px;
height: 40px;
background: rgba(0, 0, 0, 0);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
backdrop-filter: blur(5px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.playlist-trigger:hover {
background: rgba(233, 69, 96, 1);
transform: scale(1.1);
}
.playlist-trigger::before {
content: "≡";
color: Sienna;
font: 200 20px/15px ;
}
.playlist {
position: absolute;
top: 50px;
right: 0;
background: rgba(220,220,220, 0);
border-radius: 10px;
padding: 10px;
height: 150px;
overflow: hidden;
width: 300px;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
opacity: 0;
visibility: hidden;
display: flex;
flex-direction: column;
}
.playlist-container:hover .playlist {
opacity: 1;
visibility: visible;
}
.playlist-header {
margin-bottom: 10px;
color: #fff555;
text-align: center;
border-bottom: 1px solid rgba(128,0,0, 0.5);
padding-bottom: 8px;
flex-shrink: 0;
}
.playlist-items {
flex: 1;
overflow-y: auto;
padding-right: 5px;
}
.playlist-item {
padding: 8px 12px;
margin: 5px 0;
line-height: 0.7;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
font-size: 14px;
flex-shrink: 0;
}
.playlist-item:hover {
background: rgba(233, 69, 96, 0.3);
}
.playlist-item.active {
background: rgba(233, 69, 96, 0.5);
color: white;
}
/* 滚动条样式 */
.playlist-items::-webkit-scrollbar {
width: 6px;
}
.playlist-items::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
.playlist-items::-webkit-scrollbar-thumb {
background: rgba(233, 69, 96, 0.8);
border-radius: 3px;
transition: background 0.3s;
}
.playlist-items::-webkit-scrollbar-thumb:hover {
background: rgba(233, 69, 96, 0.8);
}
</style>
</head>
<body>
<div id="bj">
<!-- 歌曲信息 -->
<div class="song-info">
<div class="song-title">《秋天的枫叶》</div>
<div class="song-artist">演唱:王爱华 </div>
</div>
<div class="lyric-preview" id="lyricPreview">
<div class="prev-lyric" id="prevLyric"></div>
<div class="current-lyric" id="currentLyric"></div>
<div class="next-lyric" id="nextLyric"></div>
</div>
<div id="player" title="暂停/播放"></div>
<div class="progress-container" id="progressContainer">
<div class="progress-bar" id="progressBar"></div>
<div class="time-display">
<span id="currentTime">0:00</span>
<span id="duration">0:00</span>
</div>
</div>
<!-- 控制按钮 -->
<div class="controls">
<button class="control-btn" id="prevBtn" title="上一曲">◀◀</button>
<button class="control-btn" id="nextBtn" title="下一曲">▶▶</button>
<div class="volume-container">
<button class="control-btn" id="volumeBtn" title="静音"></button>
<div class="volume-slider" id="volumeSlider">
<div class="volume-level" id="volumeLevel"></div>
</div>
</div>
</div>
<!-- 播放列表 -->
<div class="playlist-container">
<div class="playlist-trigger" title="播放列表"></div>
<div class="playlist" id="playlist">
<h3 class="playlist-header">歌曲列表</h3>
<div class="playlist-items">
<div class="playlist-item active" data-index="0">《秋天的枫叶》演唱:王爱华</div>
<div class="playlist-item" data-index="1">《枫叶情》 歌手:林淑容</div>
</div>
</div>
</div>
<div class="loading" id="loading">加载中...</div>
<canvas id="glcanvas" width="900" height="420"></canvas>
<video id="bgVideo" src="" muted loop></video>
<!-- 音频播放器 -->
<audio id="audio"></audio>
</div>
<script>
// 歌曲数据
const songs = [
{
title: "《秋天的枫叶》",
artist: "演唱:王爱华 ",
audioUrl: "https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/01.mp3",
videoUrl: "",
lyrics: `
《秋天的枫叶》
美景与痴情的演绎
演唱:王爱华
谁给画里藏进香味
让人陶醉
谁与恋人结伴成对
把彩云追
谁用太阳的色彩把梦描绘
梦中依偎
谁用一生选择了无悔
风雨相随
枫叶红哟枫叶美
浓妆艳抹要嫁谁
嫁给层层的山
潺潺的水
未了痴情最珍贵
枫叶红哟
枫叶美
浓妆艳抹要爱谁
明知明天即将离去
为梦沉醉
LRC编辑:小辣椒
谁给画里藏进香味
让人陶醉
谁与恋人结伴成对
把彩云追
谁用太阳的色彩把梦描绘
梦中依偎
谁用一生选择了无悔
风雨相随
枫叶红哟枫叶美
浓妆艳抹要嫁谁
嫁给层层的山
潺潺的水
未了痴情最珍贵
枫叶红哟
枫叶美
浓妆艳抹要爱谁
明知明天即将离去
为梦沉醉
为梦沉醉
谢谢欣赏
`
},
{
title: "枫叶情",
artist: "林淑容",
audioUrl: "https://wj1.zp68.com:812/lxx/yunhua/2026/02/07/01.mp3",
videoUrl: "",
lyrics: `
枫叶情
歌手:林淑容
作词 : Traditional
作曲 : Traditional
一年容易又秋天
又见到枫叶一片片
你那红红的笑脸
要比枫叶还更娇艳
叫我对你又爱又怜
我们常在枫林里流连流连
爱在你我心里缠绵缠绵
一片枫叶一片情
片片都有我爱和怜
朝朝暮暮直到永远
LRC编辑:小辣椒
我爱美丽的秋天
我更爱枫叶一片片
要在片片的枫叶上
写下我俩的心愿
但愿俩情永远不变
你带给我柔情万千万千
我带给你爱意无限无限
一片枫叶一片情
愿你常记在心田
岁岁年年天上人间
~Music~
我们常在枫林里流连流连
爱在你我心里缠绵缠绵
一片枫叶一片情
片片都有我爱和怜
朝朝暮暮直到永远
谢谢欣赏
`
}
];
const state = {
currentSongIndex: 0,
currentLyricIndex: 0,
isAudioEnabled: true,
isPlaying: false,
mouseX: 0,
mouseY: 0,
isHovering: false,
lyrics: [],
hoverValue: 0,
hoverSpeed: 0.005,
lastMouseMoveTime: 0,
throttleDelay: 100,
userInteracted: false,
animationId: null,
isAnimating: false,
isDragging: false,
volume: 0.8,
isMuted: false,
staticBgImage: "https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/9F.jpg"
};
const elements = {
canvas: document.getElementById('glcanvas'),
audio: document.getElementById('audio'),
lyricPreview: document.getElementById('lyricPreview'),
prevLyric: document.getElementById('prevLyric'),
currentLyric: document.getElementById('currentLyric'),
nextLyric: document.getElementById('nextLyric'),
player: document.getElementById('player'),
bgVideo: document.getElementById('bgVideo'),
progressContainer: document.getElementById('progressContainer'),
progressBar: document.getElementById('progressBar'),
currentTime: document.getElementById('currentTime'),
duration: document.getElementById('duration'),
prevBtn: document.getElementById('prevBtn'),
nextBtn: document.getElementById('nextBtn'),
volumeBtn: document.getElementById('volumeBtn'),
volumeSlider: document.getElementById('volumeSlider'),
volumeLevel: document.getElementById('volumeLevel'),
loading: document.getElementById('loading'),
songTitle: document.querySelector('.song-title'),
songArtist: document.querySelector('.song-artist'),
playlist: document.getElementById('playlist'),
playlistItems: document.querySelectorAll('.playlist-item')
};
// ===================== 初始化检测 =====================
function initCheck() {
const gl = elements.canvas.getContext('webgl') || elements.canvas.getContext('experimental-webgl');
if (!gl) {
state.isAudioEnabled = false;
return null;
}
return gl;
}
// ===================== LRC歌词解析 =====================
function parsePureLRC(lrcText) {
const lines = [];
const lrcLines = lrcText.split('\n')
.map(line => line.trim())
.filter(line => line && !line.includes('●') && !line.includes('谢谢欣赏'));
for (const line of lrcLines) {
const timeRegex = /\[(\d{2}):(\d{2})(?:\.(\d{1,3}))?\]/g;
const text = line.replace(timeRegex, '').trim();
let timeMatch;
while ((timeMatch = timeRegex.exec(line)) !== null) {
const minutes = parseInt(timeMatch);
const seconds = parseInt(timeMatch);
const ms = timeMatch ? parseInt(timeMatch.padEnd(3, '0')) : 0;
const time = minutes * 60 + seconds + ms / 1000;
if (text) {
lines.push({ time, text });
}
}
}
return lines.sort((a, b) => a.time - b.time);
}
// ===================== 歌词跳转 =====================
function jumpToLyricByText(clickText) {
if (!clickText.trim()) return;
const targetLyric = state.lyrics.find(lyric => lyric.text === clickText.trim());
if (!targetLyric) return;
elements.audio.currentTime = targetLyric.time;
const targetIndex = state.lyrics.findIndex(lyric => lyric.text === clickText.trim());
if (targetIndex !== -1) {
state.currentLyricIndex = targetIndex;
elements.prevLyric.textContent = state.lyrics?.text || '';
elements.currentLyric.textContent = state.lyrics.text;
elements.nextLyric.textContent = state.lyrics?.text || '';
if (window.render && window.render.updateTextTexture) {
window.render.updateTextTexture(state.lyrics.text);
}
}
}
// ===================== WebGL渲染 =====================
function initWebGL(gl) {
function compileShader(src, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compilation error:', gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
const vertexShaderSource = `
attribute vec2 a_pos;
attribute vec2 a_uv;
varying vec2 v_uv;
void main() {
v_uv = a_uv;
gl_Position = vec4(a_pos, 0.9, 1.0);
}
`;
const fragmentShaderSource = `
precision highp float;
varying vec2 v_uv;
uniform sampler2D u_text;
uniform float u_time;
uniform vec2 u_mouse;
uniform float u_hover;
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);
}
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = random(i);
float b = random(i + vec2(1.0,0.0));
float c = random(i + vec2(0.0,1.0));
float d = random(i + vec2(1.0,1.0));
vec2 u = f*f*(3.0-2.0*f);
return mix(a,b,u.x) + (c-a)*u.y*(1.0-u.x) + (d-b)*u.x*u.y;
}
void main() {
vec2 correctedUV = vec2(v_uv.x, 1.0-v_uv.y);
float strength = smoothstep(0.2,1.0,correctedUV.y);
float noiseTime = u_time * 0.3;
float n = noise(vec2(correctedUV.x*5.0, (correctedUV.y*2.0 - noiseTime)*2.0));
float melt = n * 0.4 * (correctedUV.y);
float dist = distance(correctedUV, u_mouse);
float hoverWave = 0.0;
if (u_hover > 0.1) {
hoverWave = sin(dist*12.0 - u_time*6.0)*0.08*u_hover*exp(-dist*3.5) +
sin(dist*20.0 - u_time*10.0)*0.04*u_hover*exp(-dist*5.0);
}
vec2 hoverDistort = normalize(correctedUV - u_mouse) * hoverWave * (1.0 + sin(u_time*2.0)*0.1);
vec2 finalUV = vec2(
correctedUV.x + melt*0.3 + hoverDistort.x,
correctedUV.y - melt*0.8 + hoverDistort.y
);
vec4 col = texture2D(u_text, finalUV);
if (col.a > 0.1) {
float glow = smoothstep(0.8,1.0,col.a);
vec3 spectrumColor = vec3(correctedUV.y, abs(sin(u_time + correctedUV.x*5.0)), 1.0-correctedUV.y);
if (u_hover > 0.1) {
float hoverIntensity = 1.0 - smoothstep(0.0,0.1,dist);
float pulseEffect = 0.99 + 0.1*sin(u_time*4.0 + dist*8.0);
vec3 goldColor = vec3(0.99, 0.99+0.8*pulseEffect, 0.2+0.2*sin(u_time*3.0));
vec3 blueColor = vec3(0.99+0.99*sin(u_time*2.0 + dist*6.0), 0.99+0.8*pulseEffect, 0.5);
spectrumColor = mix(spectrumColor, mix(goldColor, blueColor, 0.99), hoverIntensity*u_hover*0.99);
glow += hoverIntensity*u_hover*0.99;
}
col.rgb = mix(col.rgb, spectrumColor, 0.99*glow);
// 优化粒子效果
if (u_hover > 0.1 && dist < 0.2) {
float particles = noise(correctedUV*15.0 + u_time*2.0);
if (particles > 0.85) col.rgb += vec3(1.0,0.8,0.4)*(particles-0.85)*8.0*u_hover;
float sparkles = noise(correctedUV*30.0 + u_time*4.0);
if (sparkles > 0.92 && dist < 0.15) col.rgb += vec3(0.9,0.9,1.0)*(sparkles-0.92)*6.0*u_hover;
}
}
if (u_hover > 0.1) {
float ambientGlow = 1.0 - smoothstep(0.0,0.4,dist);
float auraEffect = sin(dist*6.0 - u_time*3.0)*0.2 + 0.8;
vec3 auraColor = vec3(
0.15+0.1*sin(u_time*1.5),
0.1+0.1*sin(u_time*2.0+1.0),
0.2+0.15*sin(u_time*1.2+2.0)
);
col.rgb += auraColor*ambientGlow*u_hover*auraEffect;
float outerHalo = 1.0 - smoothstep(0.2,0.5,dist);
col.rgb += vec3(0.08,0.04,0.12)*outerHalo*u_hover*0.3;
}
gl_FragColor = col;
}
`;
const vs = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
const fs = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
const quad = new Float32Array([
-1, -1, 0, 0,
1, -1, 1, 0,
-1, 1, 0, 1,
1, 1, 1, 1
]);
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
const a_pos = gl.getAttribLocation(program, 'a_pos');
const a_uv = gl.getAttribLocation(program, 'a_uv');
gl.enableVertexAttribArray(a_pos);
gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 16, 0);
gl.enableVertexAttribArray(a_uv);
gl.vertexAttribPointer(a_uv, 2, gl.FLOAT, false, 16, 8);
const uniforms = {
u_time: gl.getUniformLocation(program, 'u_time'),
u_text: gl.getUniformLocation(program, 'u_text'),
u_mouse: gl.getUniformLocation(program, 'u_mouse'),
u_hover: gl.getUniformLocation(program, 'u_hover')
};
const textCanvas = document.createElement('canvas');
const tctx = textCanvas.getContext('2d');
textCanvas.width = elements.canvas.width;
textCanvas.height = elements.canvas.height;
const textTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, textTex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
function updateTextTexture(text) {
tctx.clearRect(0, 0, textCanvas.width, textCanvas.height);
tctx.fillStyle = '#000000';
tctx.font = 'bold 35px "Ma Shan Zheng","华文行楷","SimHei", "Arial", "sans-serif"';
tctx.textAlign = 'center';
tctx.textBaseline = '';
tctx.fillText(text || '', textCanvas.width / 2, textCanvas.height / 2);
gl.bindTexture(gl.TEXTURE_2D, textTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textCanvas);
}
// 绘制函数
function draw(t) {
if (!state.isAudioEnabled || !state.isAnimating) return;
if (state.isHovering && state.hoverValue < 1.0) {
state.hoverValue = Math.min(1.0, state.hoverValue + state.hoverSpeed);
} else if (!state.isHovering && state.hoverValue > 0.0) {
state.hoverValue = Math.max(0.0, state.hoverValue - state.hoverSpeed);
}
gl.viewport(0, 0, elements.canvas.width, elements.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
const time = t * 0.0005;
gl.uniform1f(uniforms.u_time, time);
gl.uniform2f(uniforms.u_mouse, state.mouseX, state.mouseY);
gl.uniform1f(uniforms.u_hover, state.hoverValue);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textTex);
gl.uniform1i(uniforms.u_text, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
state.animationId = requestAnimationFrame(draw);
}
return { updateTextTexture, draw};
}
// ===================== 歌词同步 =====================
function updateLyric() {
if (!state.isAudioEnabled || !state.lyrics.length || !state.isPlaying) return;
const currentTime = elements.audio.currentTime;
const { lyrics } = state;
for (let i = 0; i < lyrics.length; i++) {
const currentLyricTime = lyrics.time;
const nextLyricTime = i < lyrics.length - 1 ? lyrics.time : Infinity;
if (currentTime >= currentLyricTime && currentTime < nextLyricTime && state.currentLyricIndex !== i) {
state.currentLyricIndex = i;
if (window.render && window.render.updateTextTexture) {
window.render.updateTextTexture(lyrics.text);
}
elements.prevLyric.textContent = lyrics?.text || '';
elements.currentLyric.textContent = lyrics.text;
elements.nextLyric.textContent = lyrics?.text || '';
break;
}
}
if (state.isPlaying) {
requestAnimationFrame(updateLyric);
}
}
// ===================== 进度条更新 =====================
function updateProgress() {
if (!state.isAudioEnabled || !state.isPlaying) return;
const currentTime = elements.audio.currentTime;
const duration = elements.audio.duration;
if (duration) {
const progressPercent = (currentTime / duration) * 100;
elements.progressBar.style.width = `${progressPercent}%`;
elements.currentTime.textContent = formatTime(currentTime);
elements.duration.textContent = formatTime(duration);
}
if (state.isPlaying) {
requestAnimationFrame(updateProgress);
}
}
// ===================== 时间格式化 =====================
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
}
// ===================== 音量控制 =====================
function updateVolume() {
elements.audio.volume = state.volume;
elements.volumeLevel.style.width = `${state.volume * 100}%`;
if (state.volume === 0 || state.isMuted) {
elements.volumeBtn.textContent = '';
} else if (state.volume < 0.5) {
elements.volumeBtn.textContent = '';
} else {
elements.volumeBtn.textContent = '';
}
}
// ===================== 切换歌曲 =====================
function switchSong(index) {
if (index === state.currentSongIndex) return;
if (state.isPlaying) {
elements.audio.pause();
}
state.currentSongIndex = index;
elements.playlistItems.forEach((item, i) => {
if (i === index) {
item.classList.add('active');
} else {
item.classList.remove('active');
}
});
const currentSong = songs;
elements.songTitle.textContent = currentSong.title;
elements.songArtist.textContent = `演唱:${currentSong.artist}`;
elements.audio.src = currentSong.audioUrl;
elements.bgVideo.src = currentSong.videoUrl;
state.lyrics = parsePureLRC(currentSong.lyrics);
state.currentLyricIndex = 0;
if (state.lyrics.length > 0) {
window.render.updateTextTexture(state.lyrics.text);
elements.prevLyric.textContent = '';
elements.currentLyric.textContent = state.lyrics.text;
elements.nextLyric.textContent = state.lyrics?.text || '';
}
elements.progressBar.style.width = '0%';
elements.currentTime.textContent = '0:00';
elements.duration.textContent = '0:00';
elements.audio.load();
attemptAutoPlay();
}
// ===================== 事件绑定 =====================
function bindEvents(gl) {
window.addEventListener('resize', () => {
if (!gl) return;
const width = elements.canvas.parentElement.clientWidth * 0.95;
const height = elements.canvas.parentElement.clientHeight * 0.6;
elements.canvas.width = width;
elements.canvas.height = height;
});
elements.canvas.addEventListener('mousemove', (e) => {
const now = Date.now();
if (now - state.lastMouseMoveTime < state.throttleDelay) return;
state.lastMouseMoveTime = now;
if (state.isAudioEnabled) {
const rect = elements.canvas.getBoundingClientRect();
state.mouseX = (e.clientX - rect.left) / rect.width;
state.mouseY = 1.0 - (e.clientY - rect.top) / rect.height;
state.isHovering = true;
}
});
elements.canvas.addEventListener('mouseleave', () => {
state.isHovering = false;
});
elements.lyricPreview.addEventListener('click', (e) => {
const target = e.target;
if (target.classList.contains('prev-lyric') ||
target.classList.contains('current-lyric') ||
target.classList.contains('next-lyric')) {
const clickText = target.textContent;
jumpToLyricByText(clickText);
}
});
elements.player.addEventListener('click', function(e) {
console.log('播放按钮被点击');
e.stopPropagation();
togglePlayback();
});
elements.progressContainer.addEventListener('click', (e) => {
if (!state.isAudioEnabled) return;
const rect = elements.progressContainer.getBoundingClientRect();
const percent = (e.clientX - rect.left) / rect.width;
elements.audio.currentTime = percent * elements.audio.duration;
});
elements.progressContainer.addEventListener('mousedown', (e) => {
state.isDragging = true;
const rect = elements.progressContainer.getBoundingClientRect();
const percent = (e.clientX - rect.left) / rect.width;
elements.audio.currentTime = percent * elements.audio.duration;
});
document.addEventListener('mousemove', (e) => {
if (state.isDragging) {
const rect = elements.progressContainer.getBoundingClientRect();
const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
elements.audio.currentTime = percent * elements.audio.duration;
}
});
document.addEventListener('mouseup', () => {
state.isDragging = false;
});
elements.prevBtn.addEventListener('click', () => {
const prevIndex = state.currentSongIndex > 0 ? state.currentSongIndex - 1 : songs.length - 1;
switchSong(prevIndex);
});
elements.nextBtn.addEventListener('click', () => {
const nextIndex = state.currentSongIndex < songs.length - 1 ? state.currentSongIndex + 1 : 0;
switchSong(nextIndex);
});
elements.playlistItems.forEach((item, index) => {
item.addEventListener('click', () => {
switchSong(index);
});
});
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
togglePlayback();
} else if (e.code === 'ArrowLeft') {
elements.audio.currentTime = Math.max(0, elements.audio.currentTime - 5);
} else if (e.code === 'ArrowRight') {
elements.audio.currentTime = Math.min(elements.audio.duration, elements.audio.currentTime + 5);
} else if (e.code === 'ArrowUp') {
state.volume = Math.min(1, state.volume + 0.1);
updateVolume();
} else if (e.code === 'ArrowDown') {
state.volume = Math.max(0, state.volume - 0.1);
updateVolume();
}
});
document.addEventListener('click', () => {
state.userInteracted = true;
});
}
// ===================== 播放控制函数 =====================
function togglePlayback() {
console.log('togglePlayback 被调用,当前状态:', elements.audio.paused ? '暂停' : '播放');
if (elements.audio.paused) {
elements.audio.play().catch(error => {
console.error('播放失败:', error);
});
} else {
elements.audio.pause();
}
updatePlayerState();
}
// ===================== 更新播放状态(包含背景切换) =====================
function updatePlayerState() {
const bgContainer = document.getElementById('bj');
if (elements.audio.paused) {
// 暂停状态
elements.player.classList.remove('playing');
state.isPlaying = false;
state.isAnimating = false;
elements.bgVideo.pause();
if (state.animationId) {
cancelAnimationFrame(state.animationId);
state.animationId = null;
}
bgContainer.style.background = `#55aa55 url(${state.staticBgImage}) no-repeat center/cover`;
bgContainer.style.animationPlayState = 'paused';
elements.canvas.style.animationPlayState = 'paused';
elements.player.style.animationPlayState = 'paused';
} else {
// 播放状态
elements.player.classList.add('playing');
state.isPlaying = true;
state.isAnimating = true;
elements.bgVideo.play().catch(e => {
console.log('背景视频播放失败:', e);
});
bgContainer.style.background = "#55aa55 url(https://wj1.zp68.com:812/lxx/yunhua/2025/11/23/9F.gif) no-repeat center/cover";
bgContainer.style.animationPlayState = 'running';
elements.canvas.style.animationPlayState = 'running';
elements.player.style.animationPlayState = 'running';
if (window.render && window.render.draw) {
state.animationId = requestAnimationFrame(window.render.draw);
}
updateLyric();
updateProgress();
}
console.log('播放状态更新:', state.isPlaying ? '播放中' : '已暂停');
}
// ===================== 自动播放 =====================
function attemptAutoPlay() {
elements.loading.style.display = 'block';
const playPromise = elements.audio.play();
if (playPromise !== undefined) {
playPromise.then(() => {
elements.loading.style.display = 'none';
updatePlayerState();
}).catch(error => {
console.log('自动播放被阻止,等待用户交互');
elements.loading.style.display = 'none';
const hint = document.createElement('div');
hint.textContent = '无法播放,请更换链接或稍后再试';
hint.style.position = 'absolute';
hint.style.top = '50%';
hint.style.left = '50%';
hint.style.transform = 'translate(-50%, -50%)';
hint.style.background = 'rgba(0,0,0,1)';
hint.style.padding = '15px 30px';
hint.style.borderRadius = '10px';
hint.style.zIndex = '20';
hint.style.cursor = 'pointer';
document.getElementById('bj').appendChild(hint);
const startPlayback = () => {
elements.audio.play().then(() => {
updatePlayerState();
hint.remove();
document.removeEventListener('click', startPlayback);
});
};
hint.addEventListener('click', startPlayback);
document.addEventListener('click', startPlayback);
});
}
}
// ===================== 初始化 =====================
async function init() {
const currentSong = songs;
elements.audio.src = currentSong.audioUrl;
elements.bgVideo.src = currentSong.videoUrl;
state.lyrics = parsePureLRC(currentSong.lyrics);
const gl = initCheck();
if (!gl) {
console.error('WebGL不支持,播放器将无法正常工作');
elements.loading.textContent = 'WebGL不支持,播放器无法正常工作';
return;
}
window.render = initWebGL(gl);
bindEvents(gl);
if (state.lyrics.length > 0) {
window.render.updateTextTexture(state.lyrics.text);
elements.prevLyric.textContent = '';
elements.currentLyric.textContent = state.lyrics.text;
elements.nextLyric.textContent = state.lyrics?.text || '';
}
updateVolume();
elements.audio.addEventListener('play', updatePlayerState);
elements.audio.addEventListener('pause', updatePlayerState);
elements.audio.addEventListener('ended', () => {
const nextIndex = state.currentSongIndex < songs.length - 1 ? state.currentSongIndex + 1 : 0;
switchSong(nextIndex);
});
attemptAutoPlay();
console.log('播放器初始化完成');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
</script>
</body>
</html> @亚纶音乐工作室
学习亚纶的代码套用玩一个 因为是现成的图片,进度条我修改了一下,一键停止是背景,上面的标题字我修改后不漂亮了,就这样了
这个是偷懒制作,你看了就懂的{:4_170:} 好奇妙的歌词效果。欣赏亲爱的好帖,亚伦老师收礼开心{:4_187:} 这枫叶制作好像还是岁月的帖子里的吧,亲爱的加了人物。
标题字还会变色呢,小播也漂亮。给亲爱的点赞{:4_187:} 选的歌都是好听的,可我还是套都套不来{:4_198:} https://5b0988e595225.cdn.sohucs.com/images/20200409/db39fb96f8534ea6a6583d3e35f6721e.gif 变形的字幕很吸引人哦。 整体画面太引人入胜了!赞哦!{:4_187:} 谢谢小辣椒精彩制作,祝亚伦老师收礼开心{:4_176:}
页:
[1]