如何让多个HTML音频播放器复用同一套JS代码无需重复改写变量ID
多实例音频播放器实现方案
你之前的代码依赖全局ID和全局变量,所以只能支持单个播放器,通过类封装播放器逻辑就可以实现不限数量的多实例部署,不需要重复写变量和ID,修改方案如下:
第一步:调整HTML结构
去掉所有重复ID,改用class标识元素,删除行内onclick事件绑定,需要新增多少个播放器直接复制对应结构即可,示例代码如下:
<body> <div id="wrapper"> <!-- 播放器1 --> <fieldset> <legend>歌曲1</legend> <div class='audio-player'> <audio class="music-player" preload="metadata" loop> <source src="music/song1.mp3"> </audio> <input type="image" src="images/playButton.png" class="play-btn"> <input type="image" src="images/pauseButton.png" class="pause-btn"> <input type="image" src="images/stopButton.png" class="stop-btn"> <span class="current-time time">0:00</span> <input type="range" class="seek-slider" max="100" value="0"> <span class="duration time">0:00</span> <input type="image" src="images/volumeButton.png" class="vol-img"> <input type="range" class="vol-slider" step="0.05" min="0" max="1" value="1"> </div> </fieldset> <!-- 播放器2,需要更多直接复制该结构修改source的src即可 --> <fieldset> <legend>歌曲2</legend> <div class='audio-player'> <audio class="music-player" preload="metadata" loop> <source src="music/song2.mp3"> </audio> <input type="image" src="images/playButton.png" class="play-btn"> <input type="image" src="images/pauseButton.png" class="pause-btn"> <input type="image" src="images/stopButton.png" class="stop-btn"> <span class="current-time time">0:00</span> <input type="range" class="seek-slider" max="100" value="0"> <span class="duration time">0:00</span> <input type="image" src="images/volumeButton.png" class="vol-img"> <input type="range" class="vol-slider" step="0.05" min="0" max="1" value="1"> </div> </fieldset> </div> <script src="script.js"></script> </body>
第二步:替换JS代码为类封装版本
所有逻辑都封装在AudioPlayer类中,每个实例只会操作对应容器内的元素,状态完全隔离不会互相干扰:
class AudioPlayer { constructor(container) { // 仅查询当前播放器容器内的元素,不会跨实例冲突 this.container = container; this.audio = container.querySelector('.music-player'); this.playBtn = container.querySelector('.play-btn'); this.pauseBtn = container.querySelector('.pause-btn'); this.stopBtn = container.querySelector('.stop-btn'); this.currentTimeEl = container.querySelector('.current-time'); this.durationEl = container.querySelector('.duration'); this.seekSlider = container.querySelector('.seek-slider'); this.volImg = container.querySelector('.vol-img'); this.volSlider = container.querySelector('.vol-slider'); this.muteState = 'unmute'; this.initEvents(); this.initPlayer(); } // 时间格式化 calculateTime(secs) { const minutes = Math.floor(secs / 60); const seconds = Math.floor(secs % 60); const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`; return `${minutes}:${returnedSeconds}`; } // 显示总时长 displayDuration() { this.durationEl.textContent = this.calculateTime(this.audio.duration); } // 设置进度条最大值 setSliderMax() { this.seekSlider.max = Math.floor(this.audio.duration); } // 显示缓冲进度 displayBufferedAmount() { if (this.audio.buffered.length) { const bufferedAmount = Math.floor(this.audio.buffered.end(this.audio.buffered.length - 1)); this.container.style.setProperty('--buffered-width', `${(bufferedAmount / this.seekSlider.max) * 100}%`); } } // 初始化播放器基础配置 initPlayer() { this.audio.controls = false; if (this.audio.readyState > 0) { this.displayDuration(); this.setSliderMax(); this.displayBufferedAmount(); } else { this.audio.addEventListener('loadedmetadata', () => { this.displayDuration(); this.setSliderMax(); this.displayBufferedAmount(); }); } } // 绑定所有事件 initEvents() { // 播放控制 this.playBtn.addEventListener('click', () => this.audio.play()); this.pauseBtn.addEventListener('click', () => this.audio.pause()); this.stopBtn.addEventListener('click', () => { this.audio.pause(); this.audio.currentTime = 0; }); // 音量控制 this.volSlider.addEventListener('input', () => { this.audio.volume = this.volSlider.value; }); this.volImg.addEventListener('click', () => { if(this.muteState == 'mute') { this.volImg.src = 'images/volumeButton.png'; this.muteState = 'unmute'; this.audio.muted = false; } else { this.volImg.src = 'images/volumeButtonmute.png'; this.muteState = 'mute'; this.audio.muted = true; } }); // 进度条控制 this.audio.addEventListener('progress', () => this.displayBufferedAmount()); this.seekSlider.addEventListener('input', () => { this.currentTimeEl.textContent = this.calculateTime(this.seekSlider.value); }); this.seekSlider.addEventListener('change', () => { this.audio.currentTime = this.seekSlider.value; }); this.audio.addEventListener('timeupdate', () => { this.seekSlider.value = Math.floor(this.audio.currentTime); this.currentTimeEl.textContent = this.calculateTime(this.audio.currentTime); }); } } // 页面加载完成后自动初始化所有播放器 document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.audio-player').forEach(playerContainer => { new AudioPlayer(playerContainer); }); });
后续使用说明
- 如果需要新增播放器,直接复制HTML中的播放器结构,修改对应
audio标签内的音频地址即可,无需修改JS代码 - 原有CSS如果是用ID选择器写的,替换为对应的class选择器即可正常生效
内容的提问来源于stack exchange,提问作者RamenNoodle93
相关产品推荐
相关产品推荐

