You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单页多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>

关键功能说明

  1. 互斥播放:
    通过players数组统一管理所有播放器实例,当任意播放器开始播放时,遍历数组暂停其他正在播放的实例,并同步切换按钮图标状态。
  2. 自动切歌:
    在播放结束的finish事件中,通过DOM遍历定位当前播放器的下一个.player容器,触发其播放按钮的点击事件,实现自动切换。

内容的提问来源于stack exchange,提问作者Denys Kril

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 09:35:02