一个用AI生成的html极简音乐播放器,页面自适应,有点BUG,但是能用!
文件结构
index.html(主页)
sz_music_demo.css(主页样式)
sz_music_demo.js(主页js)
background.png/jpg(主页背景图)【不提供】
顺仔ovo-日落.mp3(音频文件.mp3、.flac 、.wav都可以)【不提供】
顺仔ovo-日落.png(音乐封面 .png、.jpg都可以)【不提供】
源代码
index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>顺仔ovo</title> <link rel="stylesheet" href="./sz_music_demo.css"> </head> <body> <div class="music-player"> <!-- 左侧控制面板 --> <div class="player-controls"> <div class="album-cover"> <img src="./顺仔ovo-日落.png" alt="专辑封面"> <div class="play-pause-btn" id="playPauseBtn"> <span class="play-icon">▶</span> <span class="pause-icon" style="display: none;">⏸</span> </div> </div> <div class="song-info"> <h2 id="songTitle">未知歌曲</h2> <p id="songArtist">未知艺术家</p> </div> <div class="progress-container"> <span id="currentTime">00:00</span> <input type="range" id="progressBar" min="0" max="100" value="0"> <span id="totalTime">00:00</span> </div> <div class="volume-control"> <span>🔊</span> <input type="range" id="volumeSlider" min="0" max="1" step="0.05" value="1"> </div> <audio id="audioPlayer" src="./顺仔ovo-日落.wav" preload="metadata"></audio> </div> <!-- 右侧歌词显示 --> <div class="lyrics-container"> <div class="lyrics-wrapper" id="lyricsWrapper"> <!-- 歌词将通过JS动态填充 --> </div> </div> </div> <!-- 嵌入LRC歌词 --> <script type="text/template" id="lrcLyrics"> [ti:日落] [ar:顺仔ovo] [00:01.12]日落 [00:04.20]作词:顺仔ovo [00:09.25]作曲:是凌子枫呀,顺仔ovo [00:21.22]缩混:顺仔Studio [00:28.90]专辑:很在乎你 [00:55.52]深情的望着你的脸 [00:59.41]沉默代替了语言 [01:03.39]你的微笑 [01:05.16]却刺痛在我心间 [01:11.48]陌生又熟悉的街 [01:15.47]刹那间熄灭的光线 [01:19.46]忽而感觉 [01:21.28]离别已出现在我的世界 [01:27.80]一遍遍说着抱歉 [01:29.67]到现在沉默寡言 [01:31.69]我们的距离 [01:33.25]已变的越来越远 [01:35.67]一个个承诺誓言 [01:37.69]回忆着往事从前 [01:39.76]甜蜜的爱恋 [01:41.18]如今已沧海桑田 [01:43.50]我变得不再洒脱 [01:47.29]可黎明变成了日落 [01:51.23]本不该说的那句分手快乐 [01:54.72]可眼泪纵横交错 [01:59.42]时间她教会我很多 [02:03.46]留下伤心与难过 [02:07.40]你不必多说 [02:09.42]全都怪我一个 [02:15.43]也许再回不到从前 [02:19.43]也许不会再爱恋 [02:23.42]没有亏欠 [02:25.39]再也不会相见 [02:31.45]~music~ [03:03.43]又到冬天 往复一年 [03:07.37]再也看不到你的笑脸 [03:11.46]时间辗转 终有离别 [03:15.00]曾经向往的化作云烟 [03:19.45]也许再见 会有寒暄 [03:23.39]离别也许就应该体面 [03:27.43]清晨的风 忙碌的街 [03:30.92]故事的主角换了人演 [03:35.77]一次次突破底线 [03:37.64]包容着彼此残缺 [03:39.66]故事就到此 [03:41.43]画上一个圆圈 [03:43.70]一罐罐柴米油盐 [03:45.67]眨眼间已过三年 [03:47.79]我们的结局 [03:49.21]就是回不到从前 [03:51.57]你现在变得很冷漠 [03:55.41]失望也许真的太多(真的太多) [03:59.41]我隐约记得你也依依不舍 [04:02.74]可你说缘分尽了 [04:07.44]爱情他把我抛弃了 [04:11.43]把我丢在角落 [04:15.33]我真的爱过 [04:17.25]还爱的很深刻 [04:23.41]也许再回不到从前 [04:27.46]也许不会再爱恋 [04:31.40]没有亏欠 [04:33.43]再也不会相见 [04:39.43]~music~ [04:55.80]一次次突破底线 [04:57.67]包容着彼此残缺 [04:59.74]故事就到此 [05:01.46]画上一个圆圈 [05:03.73]一罐罐柴米油盐 [05:05.75]眨眼间已过三年 [05:07.68]我们的结局 [05:09.52]就是回不到从前 [05:11.80]一遍遍说着抱歉 [05:13.67]到现在沉默寡言 [05:15.74]我们的距离 [05:17.25]已变的越来越远 [05:19.78]一个个承诺誓言 [05:21.70]回忆着往事从前 [05:23.67]甜蜜的爱恋 [05:25.24]如今已沧海桑田 [05:27.65]我变得不再洒脱 [05:31.29]可黎明变成了日落 [05:35.27]本不该说的那句分手快乐 [05:38.71]可眼泪纵横交错 [05:59.43]时间她教会我很多 [06:03.47]留下伤心与难过 [06:07.31]你不必多说 [06:09.43]全都怪我一个 </script> <script src="./sz_music_demo.js"></script> </body> </html>
sz_music_demo.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* 基础样式 - 确保全屏居中容器 */
html, body {
height: 100%;
width: 100%;
overflow: hidden; /* 防止滚动条 */
}
body {
/* 背景图片与模糊效果 */
background-image: url('./background.jpg');
background-size: cover;
background-position: center;
background-attachment: fixed;
margin: 0;
/* 背景模糊处理 */
position: relative;
/* 居中容器 */
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
padding: 20px;
}
body::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
z-index: -1;
}
.music-player {
display: flex;
width: 100%;
max-width: 1200px;
height: 80vh;
max-height: 600px; /* 限制最大高度,确保在大屏幕上也不会过大 */
border-radius: 15px;
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2);
overflow: hidden;
position: relative;
z-index: 1;
}
/* 左侧控制面板样式 - 深色毛玻璃效果 */
.player-controls {
flex: 0 0 35%;
max-width: 400px;
padding: 30px;
/* 深色毛玻璃效果 */
background: rgba(44, 62, 80, 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center; /* 内部元素垂直居中 */
border-right: 1px solid rgba(255, 255, 255, 0.1);
}
.album-cover {
position: relative;
width: 220px;
height: 220px;
border-radius: 50%;
overflow: hidden;
margin-bottom: 30px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
border: 4px solid rgba(255, 255, 255, 0.15);
}
.album-cover img {
width: 100%;
height: 100%;
object-fit: cover;
}
.play-pause-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-size: 24px;
color: #2c3e50;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.play-pause-btn:hover {
transform: translate(-50%, -50%) scale(1.1);
background-color: white;
}
.song-info {
text-align: center;
margin-bottom: 40px;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
width: 100%; /* 确保文本区域宽度合适 */
}
.song-info h2 {
font-size: 24px;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.song-info p {
font-size: 16px;
color: #bdc3c7;
}
.progress-container {
width: 100%;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 30px;
}
.progress-container span {
font-size: 14px;
width: 50px;
text-align: center;
}
#progressBar {
flex-grow: 1;
height: 5px;
-webkit-appearance: none;
appearance: none;
background: rgba(255, 255, 255, 0.2);
border-radius: 5px;
outline: none;
}
#progressBar::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 15px;
height: 15px;
border-radius: 50%;
background: #ecf0f1;
cursor: pointer;
transition: all 0.2s ease;
}
#progressBar::-webkit-slider-thumb:hover {
transform: scale(1.2);
background: #3498db;
}
.volume-control {
width: 100%;
display: flex;
align-items: center;
gap: 10px;
}
#volumeSlider {
flex-grow: 1;
height: 5px;
-webkit-appearance: none;
appearance: none;
background: rgba(255, 255, 255, 0.2);
border-radius: 5px;
outline: none;
}
#volumeSlider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 15px;
height: 15px;
border-radius: 50%;
background: #ecf0f1;
cursor: pointer;
transition: all 0.2s ease;
}
#volumeSlider::-webkit-slider-thumb:hover {
transform: scale(1.2);
background: #3498db;
}
/* 右侧歌词容器 - 高斯模糊毛玻璃样式 */
.lyrics-container {
flex: 0 0 65%;
padding: 30px;
overflow: hidden;
position: relative;
/* 歌词区域毛玻璃效果 */
background: rgba(255, 255, 255, 0.01);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.lyrics-wrapper {
position: absolute;
width: calc(100% - 60px);
transition: transform 0.3s ease-out;
}
.lyric-line {
padding: 10px 0;
text-align: center; /* 歌词文本水平居中 */
font-size: 18px;
color: #2c3e50;
transition: all 0.3s ease;
line-height: 1.6;
}
.lyric-line.active {
color: #2980b9;
font-size: 22px;
font-weight: 500;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* 响应式设计 */
@media (max-width: 768px) {
.music-player {
flex-direction: column;
height: auto;
max-height: 90vh;
min-height: 500px;
}
.player-controls, .lyrics-container {
flex: none;
width: 100%;
max-width: none;
}
.player-controls {
padding: 20px;
height: 45%;
border-right: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.album-cover {
width: 140px;
height: 140px;
margin-bottom: 15px;
}
.lyrics-container {
height: 55%;
}
.song-info {
margin-bottom: 20px;
}
.progress-container {
margin-bottom: 20px;
}
}
/* 专辑封面封面旋转动画 */
.album-cover {
position: relative;
width: 220px;
height: 220px;
border-radius: 50%;
overflow: hidden;
margin-bottom: 30px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
border: 4px solid rgba(255, 255, 255, 0.15);
}
/* 旋转动画定义 */
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* 播放时应用旋转动画 */
.album-cover.playing img {
animation: rotate 20s linear infinite;
}
sz_music_demo.js
document.addEventListener('DOMContentLoaded', function() {
// 获取DOM元素
const audioPlayer = document.getElementById('audioPlayer');
const playPauseBtn = document.getElementById('playPauseBtn');
const playIcon = document.querySelector('.play-icon');
const pauseIcon = document.querySelector('.pause-icon');
const progressBar = document.getElementById('progressBar');
const currentTimeDisplay = document.getElementById('currentTime');
const totalTimeDisplay = document.getElementById('totalTime');
const volumeSlider = document.getElementById('volumeSlider');
const lyricsWrapper = document.getElementById('lyricsWrapper');
const songTitle = document.getElementById('songTitle');
const songArtist = document.getElementById('songArtist');
// 获取LRC歌词
const lrcText = document.getElementById('lrcLyrics').textContent;
const lyrics = parseLRC(lrcText);
// 新增:歌词同步定时器和当前歌词索引
let lyricSyncTimer = null;
let currentLyricIndex = -1;
// 解析LRC歌词
function parseLRC(lrc) {
const lines = lrc.split('\n');
const result = [];
let title = '';
let artist = '';
// 正则表达式匹配时间 [mm:ss.xx]
const timeRegex = /\[(\d{2}):(\d{2})\.(\d{2})\]/;
for (let line of lines) {
line = line.trim();
// 解析歌曲信息
if (line.startsWith('[ti:')) {
title = line.substring(4, line.length - 1);
continue;
}
if (line.startsWith('[ar:')) {
artist = line.substring(4, line.length - 1);
continue;
}
// 解析歌词行
const match = line.match(timeRegex);
if (match) {
const minutes = parseInt(match[1]);
const seconds = parseInt(match[2]);
const milliseconds = parseInt(match[3]);
const time = minutes * 60 + seconds + milliseconds / 100;
const text = line.replace(timeRegex, '').trim();
if (text) {
result.push({ time, text });
}
}
}
// 更新歌曲信息
songTitle.textContent = title || '未知歌曲';
songArtist.textContent = artist || '未知艺术家';
return result;
}
// 渲染歌词
function renderLyrics() {
lyricsWrapper.innerHTML = '';
if (lyrics.length === 0) {
const line = document.createElement('div');
line.className = 'lyric-line';
line.textContent = '暂无歌词';
lyricsWrapper.appendChild(line);
return;
}
lyrics.forEach((lyric, index) => {
const line = document.createElement('div');
line.className = 'lyric-line';
line.textContent = lyric.text;
line.dataset.index = index;
lyricsWrapper.appendChild(line);
});
// 初始时将第一行歌词居中
setTimeout(() => {
centerLyric(0);
currentLyricIndex = 0; // 初始化当前歌词索引
}, 100); // 延迟确保DOM已渲染
}
// 居中显示指定索引的歌词
function centerLyric(index) {
const lines = document.querySelectorAll('.lyric-line');
if (index >= lines.length) return;
// 移除所有激活状态
lines.forEach(line => line.classList.remove('active'));
// 添加当前行激活状态
lines[index].classList.add('active');
// 计算偏移量使当前歌词居中
const containerHeight = document.querySelector('.lyrics-container').clientHeight;
const lineHeight = lines[index].offsetHeight;
const lineTop = lines[index].offsetTop;
// 计算需要滚动的距离
const scrollTop = lineTop - (containerHeight / 2) + (lineHeight / 2);
// 应用滚动效果
lyricsWrapper.style.transform = `translateY(-${scrollTop}px)`;
}
// 格式化时间(将秒转换为mm:ss格式)
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
// 获取专辑封面元素
const albumCover = document.querySelector('.album-cover');
// 播放/暂停切换
playPauseBtn.addEventListener('click', function() {
if (audioPlayer.paused) {
audioPlayer.play();
playIcon.style.display = 'none';
pauseIcon.style.display = 'inline';
// 播放时添加旋转类
albumCover.classList.add('playing');
// 启动歌词同步定时器
startLyricSync();
} else {
audioPlayer.pause();
playIcon.style.display = 'inline';
pauseIcon.style.display = 'none';
// 暂停时移除旋转类
albumCover.classList.remove('playing');
}
});
// 音频播放结束时停止旋转
audioPlayer.addEventListener('ended', function() {
playIcon.style.display = 'inline';
pauseIcon.style.display = 'none';
albumCover.classList.remove('playing');
// 停止歌词同步定时器
stopLyricSync();
currentLyricIndex = -1;
});
// 更新进度条和时间显示
audioPlayer.addEventListener('timeupdate', function() {
const currentTime = audioPlayer.currentTime;
const duration = audioPlayer.duration;
// 更新进度条
const progress = (currentTime / duration) * 100;
progressBar.value = progress;
// 更新时间显示
currentTimeDisplay.textContent = formatTime(currentTime);
totalTimeDisplay.textContent = formatTime(duration || 0);
});
// 音频元数据加载完成后更新总时长
audioPlayer.addEventListener('loadedmetadata', function() {
totalTimeDisplay.textContent = formatTime(audioPlayer.duration);
});
// 拖动进度条改变播放位置
progressBar.addEventListener('input', function() {
const seekTime = (this.value / 100) * audioPlayer.duration;
audioPlayer.currentTime = seekTime;
// 拖动后立即更新歌词
updateLyrics(audioPlayer.currentTime);
});
// 调整音量
volumeSlider.addEventListener('input', function() {
audioPlayer.volume = this.value;
});
// 新增:启动歌词同步定时器
function startLyricSync() {
// 先清除可能存在的定时器
stopLyricSync();
// 每500毫秒检查一次当前播放时间
lyricSyncTimer = setInterval(() => {
if (!audioPlayer.paused) {
updateLyrics(audioPlayer.currentTime);
}
}, 500);
}
// 新增:停止歌词同步定时器
function stopLyricSync() {
if (lyricSyncTimer) {
clearInterval(lyricSyncTimer);
lyricSyncTimer = null;
}
}
// 根据当前播放时间更新歌词
function updateLyrics(currentTime) {
// 找到当前应该显示的歌词索引
for (let i = 0; i < lyrics.length; i++) { // 检查当前时间是否在当前歌词和下一句歌词之间 if ( currentTime >= lyrics[i].time &&
(i === lyrics.length - 1 || currentTime < lyrics[i + 1].time)
) {
// 只有当索引变化时才更新,避免不必要的重绘
if (i !== currentLyricIndex) {
currentLyricIndex = i;
centerLyric(i);
}
break;
}
}
}
// 窗口大小变化时重新居中歌词
window.addEventListener('resize', function() {
// 找到当前激活的歌词并重新居中
const activeLine = document.querySelector('.lyric-line.active');
if (activeLine) {
const index = parseInt(activeLine.dataset.index);
centerLyric(index);
}
});
// 初始化
renderLyrics();
// 页面卸载时清理定时器
window.addEventListener('beforeunload', function() {
stopLyricSync();
});
});




