00:00
未找到歌词
‘;
return;
}
lyricsContainer.innerHTML = ”;
const fragment = document.createDocumentFragment();
lyrics.forEach((lyric, index) => {
const li = document.createElement(‘li’);
li.textContent = lyric.text;
li.dataset.time = lyric.time.toString();
// 添加原文/译文样式类
if (lyric.isOriginal) li.classList.add(‘original’);
if (lyric.isTranslation) li.classList.add(‘translation’);
// 点击歌词跳转到对应时间点
li.addEventListener(‘click’, () => {
audio.currentTime = lyric.time;
// 如果当前是暂停状态,则开始播放
if (audio.paused) {
audio.play().catch(e => console.warn(‘自动播放失败:’, e));
}
updateActiveLyric(index);
});
fragment.appendChild(li);
});
lyricsContainer.appendChild(fragment);
}
/**
* 更新当前播放歌词的高亮状态
* @param {number} index – 当前歌词的索引
*/
function updateActiveLyric(index) {
// 移除所有歌词的高亮样式
document.querySelectorAll(‘#lyrics li’).forEach((li, i) => {
li.classList.remove(‘active’, ‘active-translation’);
li.style.display = isLyricsCollapsed ? ‘none’ : ”;
// 重置样式
li.style.backgroundColor = ”;
li.style.color = ”;
li.style.fontWeight = ”;
li.style.fontSize = ”;
li.style.transform = ”;
// 恢复原始文本
if (lyrics[i]) {
li.textContent = lyrics[i].text;
}
});
const lines = document.querySelectorAll(‘#lyrics li’);
const currentLine = lines[index];
if (!currentLine) return;
// 更新当前歌词元素引用
currentLyricElement = currentLine;
// 高亮显示当前行
currentLine.classList.add(‘active’);
currentLine.style.display = ‘block’;
// 确定是否有对应的翻译行
let translationLine = null;
let translationText = ”;
// 检查是否有对应的翻译行
if (lyrics[index]) {
if (lyrics[index].isOriginal) {
if (index < lyrics.length – 1) {
if (lyrics[index + 1].isTranslation) {
translationLine = lines[index + 1];
translationText = lyrics[index + 1].text;
if (!isLyricsCollapsed) {
translationLine.classList.add('active-translation');
translationLine.style.display = 'block';
}
}
}
}
}
// 如果不是用户手动滚动,则自动滚动到当前歌词
if (!isUserScrolling) {
if (!isLyricsCollapsed) {
// 展开状态下的滚动逻辑
scrollToLyricWithTranslation(index, translationLine ? true : false);
} else {
// 折叠状态下的样式
currentLine.style.backgroundColor = 'transparent';
currentLine.style.color = '#d9534f';
currentLine.style.fontWeight = 'bold';
currentLine.style.fontSize = '1.1em';
currentLine.style.transform = 'translateX(5px)';
// 在折叠状态下拼接显示原文和翻译
if (translationText) {
// 创建原文和译文的span元素
const originalSpan = document.createElement('span');
originalSpan.textContent = lyrics[index].text;
const separatorSpan = document.createElement('span');
separatorSpan.textContent = ' | ';
separatorSpan.style.color = '#666';
separatorSpan.style.fontWeight = 'normal';
const translationSpan = document.createElement('span');
translationSpan.textContent = translationText;
translationSpan.style.color = 'var(–translation-color)';
translationSpan.style.fontStyle = 'italic';
translationSpan.style.fontSize = '0.95em';
// 清空当前行内容并添加新元素
currentLine.textContent = '';
currentLine.appendChild(originalSpan);
currentLine.appendChild(separatorSpan);
currentLine.appendChild(translationSpan);
}
}
}
}
/**
* 滚动到指定的歌词行,考虑翻译行
* @param {number} index – 歌词索引
* @param {boolean} hasTranslation – 是否有对应的翻译行
*/
function scrollToLyricWithTranslation(index, hasTranslation) {
const line = document.querySelectorAll('#lyrics li')[index];
if (!line) return;
const offsetTop = line.offsetTop;
const containerHeight = container.offsetHeight;
// 计算滚动目标位置
// 如果有翻译行,考虑额外的空间以确保翻译行也可见
const additionalSpace = hasTranslation ? line.offsetHeight : 0;
const scrollTarget = Math.max(0, offsetTop – containerHeight / 3 – additionalSpace);
container.scrollTo({
top: scrollTarget,
behavior: 'smooth'
});
}
/**
* 同步音频播放时间和歌词显示
* @param {number} currentTime – 当前播放时间(秒)
*/
function synchronizeLyricsWithAudio(currentTime) {
let foundIndex = -1;
// 查找当前时间对应的歌词
for (let i = 0; i < lyrics.length; i++) {
if (lyrics[i].time 0) {
if (lyrics[i – 1].isOriginal) {
foundIndex = i – 1; // 设置为原文索引
}
}
} else {
foundIndex = i; // 否则使用当前索引
}
} else {
// 一旦找到时间戳大于当前时间的歌词,就停止循环
break;
}
}
// 如果找到对应的歌词且索引发生变化,则更新显示
if (foundIndex >= 0) {
if (foundIndex !== currentIndex) {
currentIndex = foundIndex;
updateActiveLyric(currentIndex);
}
}
}
// 音频播放相关事件监听
audio.addEventListener(‘timeupdate’, function() {
synchronizeLyricsWithAudio(audio.currentTime);
});
audio.addEventListener(‘play’, function() {
container.classList.add(‘playing’);
customPlayer.classList.add(‘playing’);
});
audio.addEventListener(‘pause’, function() {
container.classList.remove(‘playing’);
customPlayer.classList.remove(‘playing’);
});
audio.addEventListener(‘ended’, function() {
document.querySelectorAll(‘#lyrics li’).forEach(li => {
li.classList.remove(‘active’, ‘active-translation’);
});
currentIndex = 0;
});
// 歌词容器滚动事件处理
container.addEventListener(‘scroll’, function() {
isUserScrolling = true;
clearTimeout(scrollTimeout);
// 800ms后恢复自动滚动
scrollTimeout = setTimeout(() => {
isUserScrolling = false;
}, 800);
});
// 保持波浪动画效果
container.classList.add(‘playing’);
// 播放控制相关函数
function togglePlay() {
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
}
// 更新进度条显示
function updateProgress() {
const percent = (audio.currentTime / audio.duration) * 100;
progressFilled.style.width = `${percent}%`;
currentTimeDisplay.textContent = Utils.formatTime(audio.currentTime);
}
// 进度条点击跳转
function scrub(e) {
const scrubTime = (e.offsetX / progressBar.offsetWidth) * audio.duration;
audio.currentTime = scrubTime;
}
// 显示进度条悬停时间
function showHoverTime(e) {
const hoverTime = (e.offsetX / progressBar.offsetWidth) * audio.duration;
progressHoverTime.textContent = Utils.formatTime(hoverTime);
progressHoverTime.style.display = ‘block’;
progressHoverTime.style.left = `${e.offsetX}px`;
}
// 音量控制相关函数
function toggleMute() {
audio.muted = !audio.muted;
updateVolumeIcon();
}
function changeVolume(e) {
const newVolume = e.offsetX / volumeSlider.offsetWidth;
audio.volume = Math.max(0, Math.min(1, newVolume));
volumeFilled.style.width = `${audio.volume * 100}%`;
updateVolumeIcon();
}
// 更新音量图标状态
function updateVolumeIcon() {
const volumeIcon = muteBtn.querySelector(‘.volume-icon’);
volumeIcon.className = ‘volume-icon’;
if (audio.muted || audio.volume === 0) {
volumeIcon.classList.add(‘volume-state-off’);
} else if (audio.volume < 0.3) {
volumeIcon.classList.add('volume-state-muted');
} else if (audio.volume {
totalTimeDisplay.textContent = Utils.formatTime(audio.duration);
});
progressBar.addEventListener(‘click’, scrub);
progressBar.addEventListener(‘mousemove’, showHoverTime);
progressBar.addEventListener(‘mouseout’, () => progressHoverTime.style.display = ‘none’);
muteBtn.addEventListener(‘click’, toggleMute);
volumeSlider.addEventListener(‘click’, changeVolume);
// 初始化音量图标
updateVolumeIcon();
});
/* CSS全局变量定义 */
:root {
–primary-color: #87CEEB; /* 主题色(天蓝色) */
–active-color: #d9534f; /* 激活状态颜色(红色) */
–translation-color: #337ab7; /* 翻译文本颜色(蓝色) */
–background-color: #f3f3f3; /* 背景色(浅灰色) */
–text-color: #555; /* 主要文本颜色 */
–text-secondary: #666; /* 次要文本颜色 */
–waves-opacity: 0.6; /* 波浪动画透明度 */
–border-radius: 8px; /* 通用圆角大小 */
–shadow-color: rgba(0,0,0,0.1); /* 阴影颜色 */
}
/* 播放器主容器样式 */
.music-player-container {
max-width: 100%; /* 最大宽度限制 */
margin: 0 auto; /* 水平居中 */
position: relative; /* 相对定位,作为子元素定位参考 */
background: transparent; /* 透明背景 */
padding: 5px; /* 内边距 */
border-radius: var(–border-radius); /* 圆角边框 */
width: 100%; /* 占满容器宽度 */
box-sizing: border-box; /* 边框盒模型 */
}
/* 波浪动画区域样式 */
.waves-area {
position: absolute; /* 绝对定位 */
left: 0;
right: 0;
bottom: 0;
height: 100%; /* 占满容器高度 */
z-index: 0; /* 层级设置 */
overflow: hidden; /* 隐藏溢出内容 */
border-radius: var(–border-radius); /* 圆角边框 */
pointer-events: none; /* 禁用鼠标事件 */
}
/* 波浪SVG样式 */
.waves-svg {
width: 100%;
height: 80%;
transform: none;
position: absolute;
bottom: 0;
}
/* 波浪动画效果 */
.parallax > use {
animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite;
}
/* 多层波浪动画配置 */
.parallax > use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
fill: rgba(135, 206, 235, var(–waves-opacity));
}
.parallax > use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
fill: rgba(135, 206, 235, calc(var(–waves-opacity) * 0.75));
}
.parallax > use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
fill: rgba(135, 206, 235, calc(var(–waves-opacity) * 0.5));
}
.parallax > use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
fill: rgba(135, 206, 235, calc(var(–waves-opacity) * 0.33));
}
/* 波浪移动动画关键帧 */
@keyframes move-forever {
0% { transform: translate3d(-90px, 0, 0); }
100% { transform: translate3d(85px, 0, 0); }
}
/* 自定义播放器样式 */
.custom-player {
position: relative;
width: 100%;
border-radius: var(–border-radius);
margin-bottom: 8px;
box-shadow: 0 2px 8px rgba(135, 206, 235, 0.2);
background: rgba(255, 255, 255, 0.7);
padding: 8px 12px;
box-sizing: border-box;
overflow: hidden;
}
/* 播放器背景标题样式 */
.player-background-title {
position: absolute;
left: 52px;
top: 3px;
font-size: 11px;
font-weight: 400;
white-space: nowrap;
pointer-events: none;
z-index: 0;
font-family: “PingFang SC”, “Microsoft YaHei”, “Hiragino Sans GB”, “Noto Sans SC”, “Source Han Sans CN”, sans-serif;
letter-spacing: 1px;
opacity: 0.9;
transform: scale(0.9);
transform-origin: left top;
}
.player-background-title span {
color: rgba(100, 180, 220, 0.75);
}
/* 播放器控制区域样式 */
.player-controls {
position: relative;
z-index: 1;
display: flex;
align-items: center;
gap: 12px;
height: 32px;
max-width: 100%;
}
/* 播放/暂停按钮样式 */
#play-btn {
width: 32px;
height: 32px;
border: none;
border-radius: 50%;
background: var(–primary-color);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
transition: all 0.3s ease;
}
/* 播放按钮悬停效果 */
#play-btn:hover {
background: #5CACEE;
transform: scale(1.05);
}
/* 播放按钮图标样式 */
#play-btn svg {
width: 20px;
height: 20px;
fill: white;
}
/* 播放/暂停图标切换 */
.pause-icon { display: none; }
.playing .play-icon { display: none; }
.playing .pause-icon { display: block; }
/* 进度条容器样式 */
.progress-container {
flex: 1;
position: relative;
min-width: 0;
}
/* 进度条基础样式 */
.progress-bar {
height: 3px;
background: rgba(135, 206, 235, 0.2);
border-radius: 1.5px;
cursor: pointer;
position: relative;
}
/* 进度条填充部分样式 */
.progress-filled {
height: 100%;
background: var(–primary-color);
border-radius: 1.5px;
width: 0%;
position: relative;
transition: width 0.1s ease-in-out;
}
/* 进度条拖动点样式 */
.progress-filled::after {
content: ”;
position: absolute;
right: -5px;
top: -3.5px;
width: 10px;
height: 10px;
background: var(–primary-color);
border: 2px solid white;
border-radius: 50%;
box-shadow: 0 1px 3px var(–shadow-color);
opacity: 0;
transition: opacity 0.2s ease;
}
/* 进度条悬停时显示拖动点 */
.progress-bar:hover .progress-filled::after {
opacity: 1;
}
/* 进度条时间提示样式 */
.progress-hover-time {
position: absolute;
top: -25px;
background: rgba(0,0,0,0.7);
color: white;
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
transform: translateX(-50%);
display: none;
}
/* 时间显示样式 */
.time-display {
font-size: 12px;
color: var(–text-secondary);
min-width: 85px;
text-align: center;
white-space: nowrap;
}
.time-separator {
margin: 0 4px;
opacity: 0.5;
}
/* 音量控制区域样式 */
.volume-control {
display: flex;
align-items: center;
gap: 8px;
position: relative;
min-width: 120px;
}
/* 静音按钮样式 */
#mute-btn {
width: 32px;
height: 32px;
border: none;
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}
/* 音量图标样式 */
#mute-btn svg {
width: 20px;
height: 20px;
fill: var(–primary-color);
}
/* 音量滑块容器样式 */
.volume-slider-container {
width: 80px;
position: relative;
}
/* 音量滑块基础样式 */
.volume-slider {
height: 3px;
background: rgba(135, 206, 235, 0.2);
border-radius: 1.5px;
cursor: pointer;
position: relative;
}
/* 音量滑块填充部分样式 */
.volume-filled {
height: 100%;
background: var(–primary-color);
border-radius: 1.5px;
width: 100%;
position: relative;
}
/* 音量滑块拖动点样式 */
.volume-filled::after {
content: ”;
position: absolute;
right: -6px;
top: -4px;
width: 12px;
height: 12px;
background: var(–primary-color);
border: 2px solid white;
border-radius: 50%;
box-shadow: 0 1px 3px var(–shadow-color);
opacity: 0;
transition: opacity 0.2s ease;
}
/* 音量滑块悬停时显示拖动点 */
.volume-slider:hover .volume-filled::after {
opacity: 1;
}
/* 音量图标状态样式 */
.volume-icon path { display: none; }
.volume-state-high .volume-high,
.volume-state-low .volume-low,
.volume-state-muted .volume-muted,
.volume-state-off .volume-off { display: block; }
/* 歌词容器包装样式 */
.lyrics-container-wrapper {
position: relative;
border-radius: var(–border-radius);
overflow: hidden;
}
/* 歌词滚动容器样式 */
.lyrics-scroll-container {
position: relative;
z-index: 1;
overflow-y: auto;
max-height: 350px;
border-radius: var(–border-radius);
box-shadow: 0 2px 8px var(–shadow-color);
scroll-behavior: smooth;
background: rgba(255, 255, 255, 0.7);
transition: all 0.3s ease;
}
/* 歌词折叠状态样式 */
.lyrics-scroll-container.collapsed {
max-height: 36px;
overflow: hidden;
}
.lyrics-scroll-container.collapsed #lyrics li {
text-align: center;
margin: 0;
padding: 8px 0;
line-height: 20px;
}
/* 歌词折叠按钮样式 */
.toggle-lyrics-btn {
position: absolute;
top: 2px;
right: 10px;
z-index: 3;
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(135, 206, 235, 0.3);
border-radius: 15px;
padding: 5px 12px;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
font-size: 14px;
color: var(–text-secondary);
transition: all 0.3s ease;
}
/* 折叠按钮悬停效果 */
.toggle-lyrics-btn:hover {
background: rgba(255, 255, 255, 1);
box-shadow: 0 2px 4px var(–shadow-color);
}
/* 折叠图标动画 */
.toggle-icon {
transition: transform 0.3s ease;
}
.toggle-lyrics-btn.collapsed .toggle-icon {
transform: rotate(-90deg);
}
/* 自定义滚动条样式 */
.lyrics-scroll-container::-webkit-scrollbar {
width: 4px;
}
.lyrics-scroll-container::-webkit-scrollbar-track {
background: transparent;
}
.lyrics-scroll-container::-webkit-scrollbar-thumb {
background-color: rgba(135, 206, 235, 0.3);
border-radius: 2px;
}
/* 歌词列表基础样式 */
#lyrics {
position: relative;
z-index: 2;
padding: 0;
margin: 0;
background: transparent;
padding-bottom: 100px;
width: 100%;
margin: 0 auto;
}
/* 歌词行样式 */
#lyrics li {
list-style: none;
padding: 4px 5px;
cursor: pointer;
transition: all 0.2s ease;
border-radius: 4px;
margin-bottom: 1px;
line-height: 1.5;
color: var(–text-color);
text-align: center;
width: 100%;
}
/* 歌词行悬停效果 */
#lyrics li:hover {
background-color: rgba(0,0,0,0.05);
}
/* 当前播放歌词样式 */
#lyrics li.active {
color: var(–active-color);
font-weight: bold;
font-size: 1.1em;
background-color: rgba(217, 83, 79, 0.1);
}
/* 当前播放歌词的翻译样式 */
#lyrics li.active-translation {
color: var(–translation-color);
font-style: italic;
background-color: rgba(51, 122, 183, 0.1);
}
/* 翻译歌词样式 */
#lyrics li.translation {
padding-left: 12px;
color: var(–text-secondary);
font-size: 0.95em;
border-left: none;
margin-top: -1px;
margin-bottom: 4px;
text-align: center;
}
/* 提示消息样式 */
.loading-message, .error-message, .no-lyrics {
text-align: center;
padding: 20px;
color: var(–text-secondary);
}
.error-message {
color: var(–active-color);
}
/* 播放提示样式 */
.play-prompt {
text-align: center;
padding: 8px;
background-color: rgba(255, 193, 7, 0.2);
color: #856404;
border-radius: 4px;
margin-bottom: 10px;
font-size: 14px;
transition: opacity 1s ease;
}
.play-prompt.fade-out {
opacity: 0;
}
/* 响应式布局样式 */
@media (max-width: 768px) {
/* 移动端基础样式调整 */
.music-player-container { padding: 2px; }
/* 移动端波浪动画高度调整 */
.waves-svg {
height: 40px;
min-height: 40px;
}
/* 移动端歌词容器调整 */
.lyrics-scroll-container {
max-height: 300px;
}
/* 移动端歌词列表调整 */
#lyrics { max-width: 100%; }
#lyrics li,
#lyrics li.translation,
.lyrics-scroll-container.collapsed #lyrics li {
text-align: left;
padding-left: 5px;
}
/* 移动端控制元素尺寸调整 */
.time-display { min-width: 75px; }
.volume-control { min-width: 100px; }
.volume-slider-container { width: 60px; }
}
/* 小屏幕设备样式调整 */
@media (max-width: 480px) {
.volume-slider-container { width: 40px; }
.time-display { min-width: 70px; }
.player-controls { gap: 8px; }
}
/* 大屏幕设备样式调整 */
@media (min-width: 1200px) {
}
/* 移动端特定样式 */
@media (max-width: 768px) {
/* 移动端歌词高亮效果 */
#lyrics li.active,
#lyrics li.active-translation {
transform: translateX(5px);
}
}