单页多Wavesurfer实例控制:播放互斥+自动切曲实现方案
实现多Wavesurfer播放器的互斥播放与自动切歌功能
代码实现方案
HTML结构(保持原有结构即可)
确保每个播放器容器使用统一的.player类,内部元素ID按序号递增(如playPause1对应第一首、playPauseX对应第X首),data-src正确指向音频文件地址。
<center> <p>Track 1</p> <div class="player"> <div id="controls1" class="controls"> <i class="fa-thin fa-circle-play" id="playPause1" data-src="track1.mp3"></i> </div> <div class="time"> <span id="currentTime1">00:00</span> </div> <div class="download"> <a href="">download</a> </div> <div id="waveform-body1" class="waveform-body"> <div id="loadingBox1" class="waveform-loading-box">Click play button to load and listen</div> <div id="waveform1" class="waveform"></div> </div> </div> <!-- 更多播放器实例... --> <p>Track X</p> <div class="player"> <div id="controlsX" class="controls"> <i class="fa-thin fa-circle-play" id="playPauseX" data-src="trackX.mp3"></i> </div> <div class="time"> <span id="currentTimeX">00:00</span> </div> <div class="download"> <a href="">download</a> </div> <div id="waveform-bodyX" class="waveform-body"> <div id="loadingBoxX" class="waveform-loading-box">Click play button to load and listen</div> <div id="waveformX" class="waveform"></div> </div> </div> </center>
重构后的JavaScript代码
<script> (function($) { // 存储所有Wavesurfer实例,用于全局管理 const players = []; // 时间格式化函数 const timeCalculator = function(value) { const second = Math.floor(value % 60); const minute = Math.floor((value / 60) % 60); return `${minute}:${second < 10 ? '0' + second : second}`; }; // 批量初始化所有播放器 document.querySelectorAll('.player').forEach((playerEl, index) => { const trackIndex = index + 1; // 获取当前播放器的DOM元素 const playPauseBtn = playerEl.querySelector(`#playPause${trackIndex}`); const currentTimeEl = playerEl.querySelector(`#currentTime${trackIndex}`); const loadingBoxEl = playerEl.querySelector(`#loadingBox${trackIndex}`); const waveformEl = playerEl.querySelector(`#waveform${trackIndex}`); const audioSrc = playPauseBtn.dataset.src; // 创建Wavesurfer实例 const wavesurfer = WaveSurfer.create({ container: waveformEl, backend: 'MediaElement', waveColor: '#6AA6CB', progressColor: '#487698', cursorColor: '#6AA6CB', cursorWidth: 0, barWidth: 1, responsive: true, height: 50, hideScrollbar: true, maxCanvasWidth: 4000, barRadius: 0, fillParent: true }); wavesurfer.load(audioSrc); // 关联实例与DOM元素,方便后续操作 wavesurfer.btnEl = playPauseBtn; wavesurfer.playerEl = playerEl; players.push(wavesurfer); // 播放按钮点击事件 playPauseBtn.onclick = function() { wavesurfer.playPause(); }; // 播放时暂停其他所有播放器 wavesurfer.on('play', function() { playPauseBtn.classList.remove('fa-circle-play'); playPauseBtn.classList.add('fa-circle-pause'); // 遍历实例列表,暂停当前之外的播放中的播放器 players.forEach(p => { if (p !== wavesurfer && p.isPlaying()) { p.pause(); p.btnEl.classList.remove('fa-circle-pause'); p.btnEl.classList.add('fa-circle-play'); } }); }); // 暂停事件处理 wavesurfer.on('pause', function() { playPauseBtn.classList.remove('fa-circle-pause'); playPauseBtn.classList.add('fa-circle-play'); }); // 加载进度提示 wavesurfer.on('loading', function(x) { loadingBoxEl.innerText = `Loading: ${x}%`; }); // 加载完成隐藏提示 wavesurfer.on('ready', function() { loadingBoxEl.classList.remove('waveform-loading-box'); loadingBoxEl.classList.add('waveform-loading-box-hidden'); }); // 实时更新播放时间 wavesurfer.on('audioprocess', function() { currentTimeEl.textContent = timeCalculator(wavesurfer.getCurrentTime()); }); // 拖动进度条后更新时间 wavesurfer.on('seek', function() { currentTimeEl.textContent = timeCalculator(wavesurfer.getCurrentTime()); }); // 播放结束自动切下一曲 wavesurfer.on('finish', function() { playPauseBtn.classList.remove('fa-circle-pause'); playPauseBtn.classList.add('fa-circle-play'); // 找到下一个播放器容器(跳过中间的p标签) let nextPlayer = playerEl.nextElementSibling; while (nextPlayer && !nextPlayer.classList.contains('player')) { nextPlayer = nextPlayer.nextElementSibling; } // 触发下一曲播放 if (nextPlayer) { nextPlayer.querySelector('.controls i').click(); } }); // 错误日志 wavesurfer.on('error', function(e) { console.warn(e); }); }); })(jQuery); </script>
关键功能说明
- 互斥播放:
通过players数组统一管理所有播放器实例,当任意播放器开始播放时,遍历数组暂停其他正在播放的实例,并同步切换按钮图标状态。 - 自动切歌:
在播放结束的finish事件中,通过DOM遍历定位当前播放器的下一个.player容器,触发其播放按钮的点击事件,实现自动切换。
内容的提问来源于stack exchange,提问作者Denys Kril
相关产品推荐
相关产品推荐

