html极简音乐播放器

一个用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();
    });
});
转载请注明出处,本站地址 blog.sz2016.com
文章标题: html极简音乐播放器 作者: 顺仔
本文链接:https://blog.sz2016.com/2025/10/21/html-music-player-byai/
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇