React音频播放器切换音频时旧音频未终止的问题求解
解决音频切换时旧音频不终止的问题
问题核心在于切换音频时,旧的Audio实例没有被主动暂停和清理,仍在后台播放。直接设置audioRef.current = null无法终止音频播放,必须主动调用暂停方法并重置相关状态。
修改方案
在AudioFunctionality组件中,监听currentItem变化时先处理旧音频实例,再创建新实例,同时重置播放状态:
- 当
currentItem变更时,检查是否存在旧音频实例,若存在则暂停播放、重置进度并释放资源 - 重置
isPlaying为false,确保切换音频后默认处于暂停状态 - 最后创建新的音频实例
修改后的完整代码
import over from "./over.wav"; import pretty from "./pretty1.mp3"; import diary from "./diary.mp3"; import { useState, useEffect, useRef } from "react"; import { TbPlayerPause, TbPlayerPlay } from "react-icons/tb"; const data = [ { id: 1, musicSrc: over, }, { id: 2, musicSrc: pretty, }, { id: 3, musicSrc: diary, }, ]; const App = () => { const [currentItem, setCurrentItem] = useState(2); return ( <div className="audio-container"> <BtnSet data={data} currentItem={currentItem} setCurrentItem={setCurrentItem} /> </div> ); }; const BtnSet = ({ data, currentItem, setCurrentItem }) => { function handleCurrentItem(index) { setCurrentItem(index); } return ( <> {data.map((audioItem, index) => { return ( <button key={audioItem.id} onClick={() => handleCurrentItem(index)}> Audio {index + 1} </button> ); })} <AudioFunctionality data={data} currentItem={currentItem} /> </> ); }; const AudioFunctionality = ({ data, currentItem }) => { const [isPlaying, setIsPlaying] = useState(false); const audioRef = useRef(null); useEffect(() => { // 清理旧音频实例:暂停播放+重置进度+释放资源 if (audioRef.current) { audioRef.current.pause(); audioRef.current.currentTime = 0; audioRef.current.src = ""; audioRef.current = null; } // 重置播放状态 setIsPlaying(false); // 创建新音频实例 audioRef.current = new Audio(data[currentItem].musicSrc); }, [currentItem, data]); useEffect(() => { if (!audioRef.current) return; if (isPlaying) { audioRef.current.play().catch((err) => { console.log("Failed to start playback ", err); }); } else { audioRef.current.pause(); } }, [isPlaying]); return ( <AudioControls isPlaying={isPlaying} onPlayPauseClick={setIsPlaying} /> ); }; const AudioControls = ({ isPlaying, onPlayPauseClick }) => { return ( <div> {isPlaying ? ( <button type="button" className="play-pause-btn" onClick={() => onPlayPauseClick(false)} aria-label="Pause" > <TbPlayerPause className="play-btn" /> </button> ) : ( <button type="button" className="play-pause-btn" onClick={() => onPlayPauseClick(true)} aria-label="Play" > <TbPlayerPlay /> </button> )} </div> ); }; export default App;
关键改动说明
- 在监听
currentItem的useEffect中,先对旧音频实例执行暂停、重置进度和清空资源的操作,彻底终止旧音频播放 - 调用
setIsPlaying(false),保证切换音频后播放按钮默认显示为“播放”状态 - 修复了
AudioControls中用<p>标签充当按钮的语义化问题,改为标准<button>标签
内容的提问来源于stack exchange,提问作者Don199
相关产品推荐
相关产品推荐

