楚云飞 发表于 3 天前

网页播放器(浏览器极速模式试听)

本帖最后由 楚云飞 于 2025-6-11 09:30 编辑 <br /><br /><DIV style="POSITION: relative; WIDTH: 1600px; TOP: 100px; LEFT: -460px"><IFRAME height=850 marginHeight=0 src="https://ctyh.oss-cn-qingdao.aliyuncs.com/bfq/music-player.html" frameBorder=0 width=1600 marginWidth=0 scrolling=no></IFRAME></DIV><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>

楚云飞 发表于 3 天前

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>楚天音画社区音乐播放器</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

<script>
    tailwind.config = {
      theme: {
      extend: {
          colors: {
            primary: '#C81623',
            secondary: '#2E3033',
            light: '#F5F5F5',
            dark: '#18191C',
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
      },
      }
    }
</script>

<style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
      content-visibility: auto;
      }
      .music-progress {
      height: 3px;
      background: rgba(255, 255, 255, 0.2);
      cursor: pointer;
      }
      .music-progress-bar {
      height: 100%;
      background: #C81623;
      position: relative;
      }
      .progress-handle {
      position: absolute;
      right: -7px;
      top: 50%;
      transform: translateY(-50%);
      width: 14px;
      height: 14px;
      background: white;
      border-radius: 50%;
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
      opacity: 0;
      transition: opacity 0.2s;
      }
      .music-progress:hover .progress-handle {
      opacity: 1;
      }
      .album-rotate {
      animation: rotate 20s linear infinite;
      animation-play-state: paused;
      }
      .album-rotate.play {
      animation-play-state: running;
      }
      @keyframes rotate {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
      }
      .song-item {
      transition: all 0.2s;
      }
      .song-item:hover {
      background-color: rgba(200, 22, 35, 0.1);
      }
      .song-item.active {
      color: #C81623;
      font-weight: 500;
      }
      .volume-slider {
      -webkit-appearance: none;
      height: 3px;
      background: rgba(255, 255, 255, 0.2);
      border-radius: 5px;
      outline: none;
      }
      .volume-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 12px;
      height: 12px;
      background: white;
      border-radius: 50%;
      cursor: pointer;
      transition: all 0.15s ease-in-out;
      }
      .volume-slider::-webkit-slider-thumb:hover {
      box-shadow: 0 0 0 8px rgba(255, 255, 255, 0.1);
      }
    }
</style>
</head>
<body class="bg-dark text-light min-h-screen font-sans">
<div class="container mx-auto px-4 py-8 max-w-6xl">
    <!-- 播放器标题 -->
    <div class="text-center mb-8">
      <h1 class="text- font-bold text-primary mb-2">楚天音画社区音乐播放器</h1>
      <p class="text-gray-400">试听版 - 13首精选歌曲</p>
    </div>
   
    <!-- 播放器主体 -->
    <div class="bg-secondary rounded-xl shadow-xl overflow-hidden flex flex-col md:flex-row">
      <!-- 左侧专辑和控制区 -->
      <div class="w-full md:w-1/2 p-6 flex flex-col items-center">
      <div class="relative mb-6">
          <div class="w-64 h-64 rounded-full overflow-hidden border-8 border-gray-800 shadow-lg album-container">
            <img id="albumCover" src="https://picsum.photos/seed/music1/500/500" alt="专辑封面" class="w-full h-full object-cover album-rotate">
          </div>
          <div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-16 h-16 bg-secondary rounded-full flex items-center justify-center shadow-inner">
            <div class="w-6 h-6 bg-dark rounded-full"></div>
          </div>
      </div>
      
      <div class="text-center mb-4">
          <h2 id="songTitle" class="text-xl font-semibold">歌曲标题</h2>
          <p id="songArtist" class="text-gray-400">歌手</p>
      </div>
      
      <!-- 进度条 -->
      <div class="w-full mb-6">
          <div class="flex justify-between text-xs text-gray-400 mb-1">
            <span id="currentTime">0:00</span>
            <span id="duration">0:00</span>
          </div>
          <div class="music-progress" id="progressBar">
            <div class="music-progress-bar" id="progress"></div>
          </div>
      </div>
      
      <!-- 控制按钮 -->
      <div class="w-full flex justify-between items-center">
          <button id="shuffleBtn" class="text-gray-400 hover:text-primary transition-colors">
            <i class="fa fa-random text-xl"></i>
          </button>
          <button id="prevBtn" class="text-gray-400 hover:text-primary transition-colors">
            <i class="fa fa-step-backward text-2xl"></i>
          </button>
          <button id="playBtn" class="bg-primary text-white w-14 h-14 rounded-full flex items-center justify-center shadow-lg hover:bg-primary/90 transition-all transform hover:scale-105">
            <i class="fa fa-pause text-xl ml-1"></i>
          </button>
          <button id="nextBtn" class="text-gray-400 hover:text-primary transition-colors">
            <i class="fa fa-step-forward text-2xl"></i>
          </button>
          <button id="repeatBtn" class="text-primary transition-colors">
            <i class="fa fa-repeat text-xl"></i><span class="absolute text-">1</span>
          </button>
      </div>
      
      <!-- 音量控制 -->
      <div class="w-full mt-6 flex items-center justify-center">
          <button id="muteBtn" class="text-gray-400 hover:text-primary transition-colors mr-3">
            <i class="fa fa-volume-up"></i>
          </button>
          <input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="0.7" class="volume-slider w-32">
      </div>
      </div>
      
      <!-- 右侧歌曲列表 -->
      <div class="w-full md:w-1/2 bg-dark/50 p-6">
      <div class="flex justify-between items-center mb-4">
          <h3 class="text-lg font-semibold">播放列表</h3>
          <span class="text-xs text-gray-400"><span id="songCount">0</span>/13 首</span>
      </div>
      
      <div class="overflow-y-auto max-h-" id="playlistContainer">
          <!-- 播放列表将通过JavaScript动态生成 -->
      </div>
      </div>
    </div>
   
    <!-- 页脚 -->
    <div class="mt-8 text-center text-gray-500 text-sm">
      <p>楚天音画社区音乐试听版 &copy; 2025</p>
      <p class="mt-1">本播放器仅用于演示,所有音乐版权归原作者所有</p>
    </div>
</div>

<script>
    // 音乐列表数据
    const songs = [
      { id: 1, title: "蜀山", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music1/500/500", src: "https://upfile.mp3.wf/view.php/48f19f0f6d2dbe56abab4c35f0ac2295.mp3" },
      { id: 2, title: "流沙", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music2/500/500", src: "https://upfile.mp3.wf/view.php/deb5c303021f4d65c6adabd06dbc3bc5.mp3" },
      { id: 3, title: "轮回", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music3/500/500", src: "https://upfile.mp3.wf/view.php/c6ce66a203df61f16064cda1fb874c3f.mp3" },
      { id: 4, title: "胡旋舞", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music4/500/500", src: "https://upfile.mp3.wf/view.php/f258e8a6f5391f08e4075ca4c9b37b55.mp3" },
      { id: 5, title: "精灵", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music5/500/500", src: "https://upfile.mp3.wf/view.php/c73bbd8d5aa392181f7b299c6ff1c381.mp3" },
      { id: 6, title: "聆听", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music6/500/500", src: "https://upfile.mp3.wf/view.php/108eefe959624f66fc445036d5615768.mp3" },
      { id: 7, title: "面具", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music7/500/500", src: "https://upfile.mp3.wf/view.php/65ecf225e8fc1d15e5a1fcd18b72b739.mp3" },
      { id: 8, title: "情殇", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music8/500/500", src: "https://upfile.mp3.wf/view.php/602733ae06318b30676cc93db49fe0c8.mp3" },
      { id: 9, title: "琼瑶", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music9/500/500", src: "https://upfile.mp3.wf/view.php/10536bfec13cec5adc4ea9f893a8a93d.mp3" },
      { id: 10, title: "硕人", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music10/500/500", src: "https://upfile.mp3.wf/view.php/7396e44cdf3afd149611dcbedfae00db.mp3" },
      { id: 11, title: "踏歌行", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music11/500/500", src: "https://upfile.mp3.wf/view.php/f502adf73325228ec5fa6b540d45f13b.mp3" },
      { id: 12, title: "玄鸟", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music12/500/500", src: "https://upfile.mp3.wf/view.php/7af5c946e2e438b5b8d97a028833157c.mp3" },
      { id: 13, title: "半个秋天", artist: "马久越", album: "编辑:云飞扬", cover: "https://picsum.photos/seed/music13/500/500", src: "https://upfile.mp3.wf/view.php/4c336fe14db548ba6e6fe1c57cec0eda.mp3" }
    ];
   
    // DOM元素
    const audioPlayer = new Audio();
    const playBtn = document.getElementById('playBtn');
    const prevBtn = document.getElementById('prevBtn');
    const nextBtn = document.getElementById('nextBtn');
    const shuffleBtn = document.getElementById('shuffleBtn');
    const repeatBtn = document.getElementById('repeatBtn');
    const progressBar = document.getElementById('progressBar');
    const progress = document.getElementById('progress');
    const currentTimeEl = document.getElementById('currentTime');
    const durationEl = document.getElementById('duration');
    const songTitle = document.getElementById('songTitle');
    const songArtist = document.getElementById('songArtist');
    const albumCover = document.getElementById('albumCover');
    const playlistContainer = document.getElementById('playlistContainer');
    const volumeSlider = document.getElementById('volumeSlider');
    const muteBtn = document.getElementById('muteBtn');
    const songCount = document.getElementById('songCount');
   
    // 播放器状态
    let currentSongIndex = 0;
    let isPlaying = true;
    let isShuffle = false;
    let repeatMode = 2; // 2: 列表循环
   
    // 初始化
    function init() {
      // 渲染播放列表
      renderPlaylist();
      
      // 加载第一首歌曲并自动播放
      loadSong(songs);
      
      // 更新歌曲计数
      songCount.textContent = songs.length;
      
      // 设置列表循环模式
      setRepeatMode(repeatMode);
      
      // 事件监听
      playBtn.addEventListener('click', togglePlayPause);
      prevBtn.addEventListener('click', playPrevSong);
      nextBtn.addEventListener('click', playNextSong);
      shuffleBtn.addEventListener('click', toggleShuffle);
      repeatBtn.addEventListener('click', toggleRepeat);
      progressBar.addEventListener('click', setProgress);
      audioPlayer.addEventListener('timeupdate', updateProgress);
      audioPlayer.addEventListener('ended', handleSongEnd);
      audioPlayer.addEventListener('loadedmetadata', displayDuration);
      volumeSlider.addEventListener('input', adjustVolume);
      muteBtn.addEventListener('click', toggleMute);
      
      // 尝试自动播放
      attemptAutoPlay();
    }
   
    // 尝试自动播放
    function attemptAutoPlay() {
      audioPlayer.play().catch(error => {
      // 自动播放被阻止,提示用户点击播放
      console.log('自动播放被阻止:', error);
      playBtn.classList.add('animate-pulse');
      });
    }
   
    // 渲染播放列表
    function renderPlaylist() {
      playlistContainer.innerHTML = '';
      
      songs.forEach((song, index) => {
      const songItem = document.createElement('div');
      songItem.className = `song-item p-3 flex items-center justify-between border-b border-gray-800 ${index === currentSongIndex ? 'active' : ''}`;
      songItem.innerHTML = `
          <div class="flex items-center">
            <div class="w-8 h-8 rounded overflow-hidden mr-3">
            <img src="${song.cover}" alt="${song.title}专辑封面" class="w-full h-full object-cover">
            </div>
            <div>
            <div class="font-medium">${song.title}</div>
            <div class="text-xs text-gray-400">${song.artist} - ${song.album}</div>
            </div>
          </div>
          <div class="text-gray-400">
            ${index === currentSongIndex ? '<i class="fa fa-volume-up text-primary"></i>' : '<i class="fa fa-play-circle-o"></i>'}
          </div>
      `;
      
      songItem.addEventListener('click', () => {
          if (index !== currentSongIndex) {
            currentSongIndex = index;
            loadSong(songs);
            renderPlaylist();
          } else {
            togglePlayPause();
          }
      });
      
      playlistContainer.appendChild(songItem);
      });
    }
   
    // 加载歌曲
    function loadSong(song) {
      audioPlayer.src = song.src;
      songTitle.textContent = song.title;
      songArtist.textContent = song.artist;
      albumCover.src = song.cover;
      albumCover.alt = `${song.title}专辑封面`;
      
      // 播放歌曲
      if (isPlaying) {
      audioPlayer.play();
      albumCover.classList.add('play');
      playBtn.innerHTML = '<i class="fa fa-pause text-xl ml-1"></i>';
      }
    }
   
    // 播放/暂停切换
    function togglePlayPause() {
      if (isPlaying) {
      audioPlayer.pause();
      playBtn.innerHTML = '<i class="fa fa-play text-xl ml-1"></i>';
      albumCover.classList.remove('play');
      playBtn.classList.remove('animate-pulse');
      } else {
      audioPlayer.play();
      playBtn.innerHTML = '<i class="fa fa-pause text-xl ml-1"></i>';
      albumCover.classList.add('play');
      playBtn.classList.remove('animate-pulse');
      }
      isPlaying = !isPlaying;
    }
   
    // 播放上一首
    function playPrevSong() {
      if (isShuffle) {
      currentSongIndex = getRandomIndex();
      } else {
      currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length;
      }
      loadSong(songs);
      renderPlaylist();
    }
   
    // 播放下一首
    function playNextSong() {
      if (isShuffle) {
      currentSongIndex = getRandomIndex();
      } else {
      currentSongIndex = (currentSongIndex + 1) % songs.length;
      }
      loadSong(songs);
      renderPlaylist();
    }
   
    // 随机播放索引
    function getRandomIndex() {
      let randomIndex;
      do {
      randomIndex = Math.floor(Math.random() * songs.length);
      } while (randomIndex === currentSongIndex);
      return randomIndex;
    }
   
    // 切换随机播放
    function toggleShuffle() {
      isShuffle = !isShuffle;
      shuffleBtn.classList.toggle('text-primary', isShuffle);
      shuffleBtn.classList.toggle('text-gray-400', !isShuffle);
    }
   
    // 切换循环模式
    function toggleRepeat() {
      repeatMode = (repeatMode + 1) % 3;
      setRepeatMode(repeatMode);
    }
   
    // 设置循环模式
    function setRepeatMode(mode) {
      repeatMode = mode;
      
      // 更新按钮样式和图标
      if (repeatMode === 0) {
      // 顺序播放
      repeatBtn.innerHTML = '<i class="fa fa-repeat text-xl"></i>';
      repeatBtn.classList.remove('text-primary');
      repeatBtn.classList.add('text-gray-400');
      } else if (repeatMode === 1) {
      // 单曲循环
      repeatBtn.innerHTML = '<i class="fa fa-repeat text-xl"></i>';
      repeatBtn.classList.remove('text-gray-400');
      repeatBtn.classList.add('text-primary');
      } else {
      // 列表循环
      repeatBtn.innerHTML = '<i class="fa fa-repeat text-xl"></i><span class="absolute text-">1</span>';
      repeatBtn.classList.remove('text-gray-400');
      repeatBtn.classList.add('text-primary');
      }
    }
   
    // 设置进度条
    function setProgress(e) {
      const totalWidth = this.clientWidth;
      const clickPosition = e.offsetX;
      const duration = audioPlayer.duration;
      
      audioPlayer.currentTime = (clickPosition / totalWidth) * duration;
    }
   
    // 更新进度条
    function updateProgress() {
      const { currentTime, duration } = audioPlayer;
      const progressPercent = (currentTime / duration) * 100;
      progress.style.width = `${progressPercent}%`;
      
      // 更新当前时间显示
      currentTimeEl.textContent = formatTime(currentTime);
    }
   
    // 显示歌曲时长
    function displayDuration() {
      durationEl.textContent = formatTime(audioPlayer.duration);
    }
   
    // 格式化时间
    function formatTime(seconds) {
      if (isNaN(seconds)) return '0:00';
      
      const minutes = Math.floor(seconds / 60);
      const remainingSeconds = Math.floor(seconds % 60);
      
      return `${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`;
    }
   
    // 处理歌曲结束
    function handleSongEnd() {
      if (repeatMode === 1) {
      // 单曲循环
      audioPlayer.currentTime = 0;
      audioPlayer.play();
      } else if (repeatMode === 2 || isShuffle) {
      // 列表循环或随机播放
      playNextSong();
      } else {
      // 顺序播放
      if (currentSongIndex < songs.length - 1) {
          playNextSong();
      } else {
          // 播放列表结束,停止播放
          isPlaying = false;
          playBtn.innerHTML = '<i class="fa fa-play text-xl ml-1"></i>';
          albumCover.classList.remove('play');
      }
      }
    }
   
    // 调整音量
    function adjustVolume() {
      audioPlayer.volume = volumeSlider.value;
      
      // 更新音量图标
      updateVolumeIcon();
    }
   
    // 切换静音
    function toggleMute() {
      audioPlayer.muted = !audioPlayer.muted;
      
      // 更新音量图标和滑块
      if (audioPlayer.muted) {
      volumeSlider.value = 0;
      } else {
      volumeSlider.value = audioPlayer.volume;
      }
      
      updateVolumeIcon();
    }
   
    // 更新音量图标
    function updateVolumeIcon() {
      if (audioPlayer.muted || audioPlayer.volume === 0) {
      muteBtn.innerHTML = '<i class="fa fa-volume-off"></i>';
      } else if (audioPlayer.volume < 0.5) {
      muteBtn.innerHTML = '<i class="fa fa-volume-down"></i>';
      } else {
      muteBtn.innerHTML = '<i class="fa fa-volume-up"></i>';
      }
    }
   
    // 初始化播放器
    init();
</script>
</body>
</html>
   

绿蔷薇 发表于 3 天前

撒花花
问好楚帅
{:1_153:}

绿蔷薇 发表于 3 天前

这款网页播放器好漂亮
谢谢楚帅代码分享,给力哈

绿蔷薇 发表于 3 天前

音乐薇听不到呢~~;P

绿蔷薇 发表于 3 天前

换个时间段再来~~{:S16:}

圊圊淥詶 发表于 3 天前

哇哦,这个很牛啊,而且代码都贴出来了呀,
好漂亮哦这播放器,哈哈~~

圊圊淥詶 发表于 3 天前

请教云飞啊,如果我要做的话是不是只要在代码上换链接换文字就可以了?
如果是这样的话,等我有空了也去玩玩,
这个播放器好看的~~

圊圊淥詶 发表于 3 天前

谢谢云飞啊,辛苦了,做这个应该很费功夫吧;P

圊圊淥詶 发表于 3 天前

绿蔷薇 发表于 2025-6-11 14:08
音乐薇听不到呢~~

很难得哇,我这次能听到诶:lol
页: [1] 2
查看完整版本: 网页播放器(浏览器极速模式试听)