搜索结果

×

搜索结果将在这里显示。

💛 CD风格音乐播放器 - 带频谱显示

用元宝写了一个带蘋谱的音乐播放器,感觉还可以,,有需要的可以拿去
注意 音乐和HTML 上传同一根目录里面 不然意想不到的结果 哈哈。。。
先上效果图

代码


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CD风格音乐播放器 - 带频谱显示</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            color: #fff;
            padding: 20px;
        }

        .music-player {
            width: 100%;
            max-width: 980px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
            backdrop-filter: blur(10px);
            text-align: center;
            display: flex;
        }

        .right-box{
             width:calc(100% - 300px);
        }

        .album-cover-container {
            position: relative;
            width: 250px;
            height: 250px;
            margin: 0 auto 25px;
            margin-right:50px;
        }

        .album-cover {
            width: 100%;
            height: 100%;
            border-radius: 50%;
            object-fit: cover;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
            border: 8px solid rgba(255, 255, 255, 0.1);
            transition: transform 0.3s ease;
            cursor: pointer;
        }

        .cd-center {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 40px;
            height: 40px;
            background: #000;
            border-radius: 50%;
            z-index: 2;
            box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
        }

        .needle {
            position: absolute;
            top: -10px;
            left: 110%;
            transform: translateX(-50%) rotate(0deg);
            width: 4px;
            height: 160px;
            background: #8b4513;
            border-radius: 2px;
            transform-origin: top center;
            transition: transform 0.5s ease;
            z-index: 1;
        }

        .needle-head {
            position: absolute;
            top: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 15px;
            height: 15px;
            background: #a0522d;
            border-radius: 50%;
        }

        .needle.playing {
            transform: translateX(-50%) rotate(25deg);
        }

        .rotating {
            animation: rotate 10s linear infinite;
        }

        @keyframes rotate {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }

        .song-info {
            margin-bottom: 20px;
        }

        .song-title {
            font-size: 22px;
            font-weight: bold;
            margin-bottom: 5px;
        }

        .song-artist {
            font-size: 16px;
            color: #ccc;
        }

        /* 频谱显示区域 */
        .spectrum-container {
            width: 100%;
            height: 80px;
            margin-bottom: 15px;
            position: relative;
            overflow: hidden;
            background: rgba(0, 0, 0, 0.2);
            border-radius: 8px;
        }

        .spectrum-canvas {
            width: 100%;
            height: 100%;
            display: block;
        }

        .progress-container {
            width: 100%;
            margin-bottom: 25px;
            position: relative;
        }

        .progress-bar {
            width: 100%;
            height: 6px;
            background: rgba(255, 255, 255, 0.2);
            border-radius: 3px;
            overflow: visible;
            cursor: pointer;
            position: relative;
        }

        .progress {
            width: 0%;
            height: 100%;
            background: linear-gradient(90deg,#ff00ca,#00ffe7);
            border-radius: 3px;
            transition: width 0.1s linear;
            position: relative;
        }

        .time-display {
            position: relative;
            width: 100%;
            height: 15px;
            margin-top: -20px;
        }

        .current-time {
            font-size: 14px;
            color: #ffb300;
            font-weight: bold;
            position: absolute;
            left: 0;
            transform: translateX(-50%);
            transition: left 0.1s linear;
            min-width: 45px;
            text-align: center;
            z-index: 10;
        }

        .total-time {
            font-size: 14px;
            color: #00ffe7;
            position: absolute;
            left: 0;
            transform: translateX(-50%);
            transition: left 0.1s linear;
            min-width: 45px;
            text-align: center;
            z-index: 5;
            margin-top: 20px;
        }

        .controls {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 20px;
        }

        .control-btn {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.1);
            border: none;
            color: white;
            font-size: 20px;
            cursor: pointer;
            display: flex;
            justify-content: center;
            align-items: center;
            transition: all 0.3s ease;
        }

        .control-btn:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: scale(1.1);
        }

        .play-pause {
            width: 60px;
            height: 60px;
            background: #4cc9f0;
            font-size: 24px;
        }

        .play-pause:hover {
            background: #3aa8d0;
        }

        .loading {
            color: #ccc;
            font-size: 14px;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="music-player">
        <div class="album-cover-container">
            <div class="needle" id="needle">
                <div class="needle-head"></div>
            </div>
            <img src="https://picsum.photos/400/400?random=1" alt="专辑封面" class="album-cover" id="albumCover">
            <div class="cd-center"></div>
        </div>

        <div class="right-box">

        <div class="song-info">
            <div class="song-title" id="songTitle">夏日微风</div>
            <div class="song-artist" id="songArtist">林小风</div>
        </div>

        <!-- 频谱显示区域 -->
        <div class="spectrum-container">
            <canvas id="spectrumCanvas" class="spectrum-canvas"></canvas>
        </div>

        <div class="progress-container">
            <div class="progress-bar" id="progressBar">
                <div class="progress" id="progress"></div>
            </div>
            <div class="time-display">
                <span class="current-time" id="currentTime">0:00</span>
                <span class="total-time" id="totalTime"> - 0:00</span>
            </div>
            <div class="loading" id="loadingText">加载音频中...</div>
        </div>

        <div class="controls">
            <button class="control-btn" id="prevBtn">⏮</button>
            <button class="control-btn play-pause" id="playPauseBtn">▶</button>
            <button class="control-btn" id="nextBtn">⏭</button>
        </div>

        <audio id="audioPlayer" preload="metadata">
            <source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg">
            您的浏览器不支持音频播放。
        </audio>

        </div>
    </div>

    <script>
        // 获取DOM元素
        const audioPlayer = document.getElementById('audioPlayer');
        const albumCover = document.getElementById('albumCover');
        const needle = document.getElementById('needle');
        const playPauseBtn = document.getElementById('playPauseBtn');
        const prevBtn = document.getElementById('prevBtn');
        const nextBtn = document.getElementById('nextBtn');
        const progressBar = document.getElementById('progressBar');
        const progress = document.getElementById('progress');
        const currentTimeEl = document.getElementById('currentTime');
        const totalTimeEl = document.getElementById('totalTime');
        const songTitle = document.getElementById('songTitle');
        const songArtist = document.getElementById('songArtist');
        const loadingText = document.getElementById('loadingText');
        const spectrumCanvas = document.getElementById('spectrumCanvas');
        const ctx = spectrumCanvas.getContext('2d');

        // 设置Canvas尺寸
        spectrumCanvas.width = spectrumCanvas.offsetWidth;
        spectrumCanvas.height = spectrumCanvas.offsetHeight;

        // 模拟音乐数据
        const playlist = [
            {
                    title: "酒干倘卖无DJ",
                    artist: "网络",
                    src: "https://pan.5blog.cn/view.php/21367832cf5f5aba290cd3a4c9abdcdb.mp3",
                    cover: "https://picsum.photos/id/1025/400/400",
            },
            {
                    title: " 骗子动嘴傻子动心 (DJ版)",
                    artist: "大美",
                    src: "https://pan.5blog.cn/view.php/19db7cd9c8f44770d0c1fd293b266a23.mp3",
                    cover: "https://picsum.photos/id/1035/400/400",
            },
            {
                    title: "爱情诺曼底dj-张小易",
                    artist: "张小易",
                    src: "https://pan.5blog.cn/view.php/766beaf43337954eb0029be7e201a23d.mp3",
                    cover: "https://picsum.photos/id/1040/400/400",
            }
        ];

        let currentSongIndex = 0;
        let audioContext, analyser, dataArray, bufferLength;
        let isPlaying = false;

        // 格式化时间(秒 -> 分:秒)[1,5](@ref)
        function formatTime(seconds) {
            if (isNaN(seconds) || seconds === Infinity) return "0:00";

            const mins = Math.floor(seconds / 60);
            const secs = Math.floor(seconds % 60);
            return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
        }

        // 初始化音频分析器 [6,7](@ref)
        function initAudioAnalyzer() {
            // 创建音频上下文
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
            analyser = audioContext.createAnalyser();

            // 创建音频源节点
            const source = audioContext.createMediaElementSource(audioPlayer);

            // 连接分析器
            source.connect(analyser);
            analyser.connect(audioContext.destination);

            // 设置FFT大小
            analyser.fftSize = 256;
            bufferLength = analyser.frequencyBinCount;
            dataArray = new Uint8Array(bufferLength);
        }

        // 绘制频谱 [6,7](@ref)
        function drawSpectrum() {
            if (!isPlaying || !analyser) return;

            requestAnimationFrame(drawSpectrum);

            // 获取频率数据
            analyser.getByteFrequencyData(dataArray);

            // 清除画布
            ctx.clearRect(0, 0, spectrumCanvas.width, spectrumCanvas.height);

            // 计算条宽和间距
            const barWidth = (spectrumCanvas.width / bufferLength) * 2.5;
            let x = 0;

            for (let i = 0; i < bufferLength; i++) {
                // 计算条高
                const barHeight = (dataArray[i] / 255) * spectrumCanvas.height;

                // 创建渐变颜色
                const gradient = ctx.createLinearGradient(0, 0, 0, spectrumCanvas.height);
                gradient.addColorStop(0, '#4cc9f0');
                gradient.addColorStop(0.5, '#3aa8d0');
                gradient.addColorStop(1, '#1a8bb8');

                // 绘制频谱条
                ctx.fillStyle = gradient;
                ctx.fillRect(
                    x,
                    spectrumCanvas.height - barHeight,
                    barWidth - 1,
                    barHeight
                );

                x += barWidth + 1;
            }
        }

        // 更新播放器信息
        function updatePlayerInfo() {
            const song = playlist[currentSongIndex];
            songTitle.textContent = song.title;
            songArtist.textContent = song.artist;
            albumCover.src = song.cover;
            audioPlayer.src = song.src;

            loadingText.style.display = 'block';
            totalTimeEl.textContent = "0:00";
            currentTimeEl.textContent = "0:00";
            progress.style.width = "0%";
            currentTimeEl.style.left = "0px";
            totalTimeEl.style.left = "0px";

            // 清除Canvas
            ctx.clearRect(0, 0, spectrumCanvas.width, spectrumCanvas.height);

            // 等待音频加载完成
            audioPlayer.load();

            // 加载音频元数据 [1](@ref)
            audioPlayer.addEventListener('loadedmetadata', function() {
                totalTimeEl.textContent = formatTime(audioPlayer.duration);
                loadingText.style.display = 'none';
            });
        }

        // 播放/暂停音乐 [2,4](@ref)
        function togglePlayPause() {
            if (audioPlayer.paused) {
                // 初始化音频分析器
                if (!audioContext) {
                    initAudioAnalyzer();
                }

                // 恢复音频上下文(某些浏览器需要用户交互后)[6](@ref)
                if (audioContext.state === 'suspended') {
                    audioContext.resume();
                }

                audioPlayer.play().then(() => {
                    playPauseBtn.innerHTML = '⏸';
                    albumCover.classList.add('rotating');
                    needle.classList.add('playing');
                    isPlaying = true;

                    // 开始绘制频谱
                    drawSpectrum();
                }).catch(error => {
                    console.error('播放失败:', error);
                    loadingText.textContent = '播放失败,请点击重试';
                });
            } else {
                audioPlayer.pause();
                playPauseBtn.innerHTML = '▶';
                albumCover.classList.remove('rotating');
                needle.classList.remove('playing');
                isPlaying = false;
            }
        }

        // 点击封面控制播放/暂停
        albumCover.addEventListener('click', togglePlayPause);

        // 播放/暂停按钮事件
        playPauseBtn.addEventListener('click', togglePlayPause);

        // 上一首 [4,5](@ref)
        prevBtn.addEventListener('click', function() {
            currentSongIndex = (currentSongIndex - 1 + playlist.length) % playlist.length;
            updatePlayerInfo();
            if (!audioPlayer.paused) {
                audioPlayer.play();
            }
        });

        // 下一首 [4,5](@ref)
        nextBtn.addEventListener('click', function() {
            currentSongIndex = (currentSongIndex + 1) % playlist.length;
            updatePlayerInfo();
            if (!audioPlayer.paused) {
                audioPlayer.play();
            }
        });

        // 更新进度条和时间显示 [1,2](@ref)
        audioPlayer.addEventListener('timeupdate', function() {
            const currentTime = audioPlayer.currentTime;
            const duration = audioPlayer.duration;

            if (duration && !isNaN(duration) && duration !== Infinity) {
                const progressPercent = (currentTime / duration) * 100;
                progress.style.width = `${progressPercent}%`;
                currentTimeEl.textContent = formatTime(currentTime);
                totalTimeEl.textContent = formatTime(duration);

                // 更新当前时间和总时间位置
                const progressBarWidth = progressBar.offsetWidth;
                const timePos = (progressPercent / 100) * progressBarWidth;
                currentTimeEl.style.left = `${timePos}px`;
                totalTimeEl.style.left = `${timePos}px`;

                // 边界检测,确保时间显示不重叠
                const minDistance = 30; // 最小间距
                if (timePos < progressBarWidth / 2) {
                    currentTimeEl.style.transform = 'translateX(-50%)';
                    totalTimeEl.style.transform = 'translateX(-50%)';
                    currentTimeEl.style.marginTop = '0px';
                    totalTimeEl.style.marginTop = '20px';
                } else {
                    currentTimeEl.style.transform = 'translateX(-50%)';
                    totalTimeEl.style.transform = 'translateX(-50%)';
                    currentTimeEl.style.marginTop = '20px';
                    totalTimeEl.style.marginTop = '0px';
                }
            }
        });

        // 点击进度条跳转 [2](@ref)
        progressBar.addEventListener('click', function(e) {
            const rect = progressBar.getBoundingClientRect();
            const clickX = e.clientX - rect.left;
            const width = rect.width;
            const duration = audioPlayer.duration;

            if (duration && !isNaN(duration) && duration !== Infinity) {
                audioPlayer.currentTime = (clickX / width) * duration;
            }
        });

        // 歌曲结束时自动下一首 [4](@ref)
        audioPlayer.addEventListener('ended', function() {
            currentSongIndex = (currentSongIndex + 1) % playlist.length;
            updatePlayerInfo();
            audioPlayer.play();
        });

        // 音频加载错误处理
        audioPlayer.addEventListener('error', function() {
            loadingText.textContent = '音频加载失败,请检查网络连接';
        });

        // 窗口大小变化时调整Canvas尺寸 [6](@ref)
        window.addEventListener('resize', function() {
            spectrumCanvas.width = spectrumCanvas.offsetWidth;
            spectrumCanvas.height = spectrumCanvas.offsetHeight;
        });

        // 初始化播放器
        updatePlayerInfo();
    </script>
</body>
</html>

演示效果

https://pan.5blog.cn/view.php/332cedea8a906b2f24868b7393bef022.html

阅读:73
发布时间:
请先 登录 再评论