音乐播放器实现:前端HTML,CSS,JavaScript综合大项目

以下是一个完整的前端音乐播放器综合项目,使用纯 HTML + CSS + JavaScript 实现(无任何框架),功能较为全面,适合作为大项目练习或简历展示。

项目功能

  • 播放 / 暂停
  • 上一首 / 下一首
  • 进度条(可拖动跳转)
  • 音量控制(可拖动)
  • 随机播放 / 循环模式切换
  • 歌单展示 & 点击切歌
  • 歌曲封面旋转动画
  • 响应式布局(手机 / 平板 / 桌面适配)
  • 时间显示(当前时间 / 总时长)
  • 歌曲信息动态切换

完整代码(单文件版,易复制运行)

将下面代码保存为 index.html,然后准备一个 music/ 文件夹放 mp3 文件和封面图,即可直接在浏览器打开运行。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>极简音乐播放器</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"/>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      color: white;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 20px;
    }

    .player {
      background: rgba(255, 255, 255, 0.12);
      backdrop-filter: blur(10px);
      border-radius: 24px;
      padding: 32px;
      width: 100%;
      max-width: 420px;
      box-shadow: 0 20px 40px rgba(0,0,0,0.4);
      text-align: center;
    }

    .cover {
      width: 220px;
      height: 220px;
      margin: 0 auto 24px;
      border-radius: 16px;
      overflow: hidden;
      box-shadow: 0 15px 35px rgba(0,0,0,0.5);
      position: relative;
    }

    .cover img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform 0.6s ease;
    }

    .cover.playing img {
      animation: rotate 20s linear infinite;
    }

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

    h2 {
      font-size: 1.6rem;
      margin-bottom: 8px;
      font-weight: 600;
    }

    .artist {
      font-size: 1rem;
      opacity: 0.8;
      margin-bottom: 28px;
    }

    .progress-container {
      height: 6px;
      background: rgba(255,255,255,0.2);
      border-radius: 10px;
      margin: 20px 0 10px;
      cursor: pointer;
      position: relative;
    }

    .progress {
      background: #fff;
      width: 0%;
      height: 100%;
      border-radius: 10px;
      transition: width 0.1s linear;
    }

    .time {
      display: flex;
      justify-content: space-between;
      font-size: 0.85rem;
      opacity: 0.9;
      margin-bottom: 20px;
    }

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

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

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

    .btn.play-pause {
      font-size: 1.8rem;
      width: 70px;
      height: 70px;
      background: rgba(255,255,255,0.25);
    }

    .volume-container {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-top: 20px;
    }

    .volume-bar {
      flex: 1;
      height: 6px;
      background: rgba(255,255,255,0.2);
      border-radius: 10px;
      cursor: pointer;
      position: relative;
    }

    .volume-progress {
      background: #fff;
      width: 70%;
      height: 100%;
      border-radius: 10px;
    }

    .playlist {
      margin-top: 32px;
      max-height: 240px;
      overflow-y: auto;
    }

    .song-item {
      display: flex;
      align-items: center;
      padding: 12px;
      border-radius: 12px;
      margin-bottom: 8px;
      cursor: pointer;
      transition: all 0.2s;
    }

    .song-item:hover,
    .song-item.active {
      background: rgba(255,255,255,0.18);
    }

    .song-item img {
      width: 50px;
      height: 50px;
      border-radius: 8px;
      margin-right: 16px;
      object-fit: cover;
    }

    .song-info {
      text-align: left;
      flex: 1;
    }

    .song-title {
      font-weight: 500;
    }

    .song-artist {
      font-size: 0.85rem;
      opacity: 0.8;
    }

    /* 滚动条美化 */
    .playlist::-webkit-scrollbar {
      width: 6px;
    }

    .playlist::-webkit-scrollbar-thumb {
      background: rgba(255,255,255,0.4);
      border-radius: 10px;
    }
  </style>
</head>
<body>

<div class="player">
  <div class="cover" id="cover">
    <img id="coverImg" src="https://images.unsplash.com/photo-1611339555312-e607c8352fd7?w=500" alt="cover">
  </div>

  <h2 id="title">歌曲标题</h2>
  <p class="artist" id="artist">歌手</p>

  <div class="progress-container" id="progressContainer">
    <div class="progress" id="progress"></div>
  </div>

  <div class="time">
    <span id="currentTime">0:00</span>
    <span id="duration">0:00</span>
  </div>

  <div class="controls">
    <button class="btn" id="shuffleBtn" title="随机播放"><i class="fas fa-random"></i></button>
    <button class="btn" id="prev"><i class="fas fa-backward"></i></button>
    <button class="btn play-pause" id="play"><i class="fas fa-play"></i></button>
    <button class="btn" id="next"><i class="fas fa-forward"></i></button>
    <button class="btn" id="repeatBtn" title="循环"><i class="fas fa-redo"></i></button>
  </div>

  <div class="volume-container">
    <i class="fas fa-volume-down"></i>
    <div class="volume-bar" id="volumeBar">
      <div class="volume-progress" id="volumeProgress"></div>
    </div>
  </div>

  <div class="playlist" id="playlist">
    <!-- 歌单动态生成 -->
  </div>
</div>

<audio id="audio"></audio>

<script>
  const audio = document.getElementById('audio');
  const playBtn = document.getElementById('play');
  const prevBtn = document.getElementById('prev');
  const nextBtn = document.getElementById('next');
  const titleEl = document.getElementById('title');
  const artistEl = document.getElementById('artist');
  const coverImg = document.getElementById('coverImg');
  const progressContainer = document.getElementById('progressContainer');
  const progress = document.getElementById('progress');
  const currentTimeEl = document.getElementById('currentTime');
  const durationEl = document.getElementById('duration');
  const volumeBar = document.getElementById('volumeBar');
  const volumeProgress = document.getElementById('volumeProgress');
  const playlistEl = document.getElementById('playlist');
  const cover = document.getElementById('cover');
  const shuffleBtn = document.getElementById('shuffleBtn');
  const repeatBtn = document.getElementById('repeatBtn');

  // 歌曲数据(可自行扩展)
  const songs = [
    {
      title: "Despacito",
      artist: "Luis Fonsi ft. Daddy Yankee",
      src: "music/despacito.mp3",
      cover: "https://images.unsplash.com/photo-1611339555312-e607c8352fd7?w=300"
    },
    {
      title: "Shape of You",
      artist: "Ed Sheeran",
      src: "music/shape-of-you.mp3",
      cover: "https://images.unsplash.com/photo-1493225454679-181216a3b5b0?w=300"
    },
    {
      title: "Blinding Lights",
      artist: "The Weeknd",
      src: "music/blinding-lights.mp3",
      cover: "https://images.unsplash.com/photo-1557672172-298e090bd0f1?w=300"
    },
    // 添加更多歌曲...
  ];

  let currentSong = 0;
  let isPlaying = false;
  let isShuffle = false;
  let repeatMode = 'none'; // none / one / all

  function loadSong(index) {
    const song = songs[index];
    titleEl.textContent = song.title;
    artistEl.textContent = song.artist;
    audio.src = song.src;
    coverImg.src = song.cover;

    // 高亮当前歌曲
    document.querySelectorAll('.song-item').forEach((el,i) => {
      el.classList.toggle('active', i === index);
    });
  }

  function playSong() {
    audio.play().catch(e => console.log("播放失败", e));
    playBtn.querySelector('i').classList.replace('fa-play', 'fa-pause');
    cover.classList.add('playing');
    isPlaying = true;
  }

  function pauseSong() {
    audio.pause();
    playBtn.querySelector('i').classList.replace('fa-pause', 'fa-play');
    cover.classList.remove('playing');
    isPlaying = false;
  }

  function togglePlay() {
    isPlaying ? pauseSong() : playSong();
  }

  function prevSong() {
    currentSong = (currentSong - 1 + songs.length) % songs.length;
    loadSong(currentSong);
    playSong();
  }

  function nextSong() {
    if (isShuffle) {
      let random = Math.floor(Math.random() * songs.length);
      while (random === currentSong) random = Math.floor(Math.random() * songs.length);
      currentSong = random;
    } else {
      currentSong = (currentSong + 1) % songs.length;
    }
    loadSong(currentSong);
    playSong();
  }

  // 更新进度条
  audio.addEventListener('timeupdate', () => {
    if (!audio.duration) return;
    const percent = (audio.currentTime / audio.duration) * 100;
    progress.style.width = percent + '%';

    currentTimeEl.textContent = formatTime(audio.currentTime);
    durationEl.textContent = formatTime(audio.duration);
  });

  function formatTime(seconds) {
    const min = Math.floor(seconds / 60);
    const sec = Math.floor(seconds % 60);
    return `${min}:${sec < 10 ? '0' : ''}${sec}`;
  }

  // 点击进度条跳转
  progressContainer.addEventListener('click', e => {
    const width = progressContainer.clientWidth;
    const clickX = e.offsetX;
    audio.currentTime = (clickX / width) * audio.duration;
  });

  // 音量控制
  volumeBar.addEventListener('click', e => {
    const width = volumeBar.clientWidth;
    const clickX = e.offsetX;
    const vol = clickX / width;
    audio.volume = vol;
    volumeProgress.style.width = vol * 100 + '%';
  });

  // 自动下一首
  audio.addEventListener('ended', () => {
    if (repeatMode === 'one') {
      audio.currentTime = 0;
      playSong();
    } else if (repeatMode === 'all' || isShuffle) {
      nextSong();
    } else {
      if (currentSong < songs.length - 1) nextSong();
    }
  });

  // 歌单渲染
  function renderPlaylist() {
    playlistEl.innerHTML = '';
    songs.forEach((song, i) => {
      const item = document.createElement('div');
      item.classList.add('song-item');
      if (i === currentSong) item.classList.add('active');

      item.innerHTML = `
        <img src="${song.cover}" alt="">
        <div class="song-info">
          <div class="song-title">${song.title}</div>
          <div class="song-artist">${song.artist}</div>
        </div>
      `;

      item.addEventListener('click', () => {
        currentSong = i;
        loadSong(i);
        playSong();
      });

      playlistEl.appendChild(item);
    });
  }

  // 模式切换
  shuffleBtn.addEventListener('click', () => {
    isShuffle = !isShuffle;
    shuffleBtn.style.color = isShuffle ? '#00ff9d' : 'white';
  });

  repeatBtn.addEventListener('click', () => {
    if (repeatMode === 'none') {
      repeatMode = 'all';
      repeatBtn.innerHTML = '<i class="fas fa-redo"></i>';
      repeatBtn.title = '列表循环';
    } else if (repeatMode === 'all') {
      repeatMode = 'one';
      repeatBtn.innerHTML = '<i class="fas fa-redo-alt"></i>';
      repeatBtn.title = '单曲循环';
    } else {
      repeatMode = 'none';
      repeatBtn.innerHTML = '<i class="fas fa-redo"></i>';
      repeatBtn.title = '不循环';
    }
  });

  // 事件绑定
  playBtn.addEventListener('click', togglePlay);
  prevBtn.addEventListener('click', prevSong);
  nextBtn.addEventListener('click', nextSong);

  // 初始化
  loadSong(currentSong);
  renderPlaylist();
  audio.volume = 0.7;
  volumeProgress.style.width = '70%';
</script>

</body>
</html>

如何扩展这个项目(进阶方向)

  1. 本地文件上传:使用 <input type="file" multiple> + File API 读取本地音乐
  2. 歌词同步:解析 LRC 文件,结合 timeupdate 事件显示
  3. 均衡器:使用 Web Audio API 实现简单 equalizer
  4. 播放列表管理:支持拖拽排序、增删歌曲(localStorage 保存)
  5. 主题切换:明暗模式、自定义背景
  6. PWA 支持:添加 manifest 和 service worker 实现离线播放
  7. 搜索功能:在歌单中实时过滤歌曲

小建议

  • 准备 3–5 首 mp3 + 对应封面图,放在 music/ 文件夹
  • 替换 songs 数组里的 src 和 cover 路径
  • 想更美观?可以参考 neumorphism、glassmorphism 或 3D 卡片风格

祝你完成一个漂亮的音乐播放器项目!如果需要添加某个具体功能(歌词、拖拽排序、夜间模式等),可以告诉我,我帮你继续完善代码。

文章已创建 4631

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部