更改音频源后 属性,之前设置的流继续播放

After changing audio source property, previously set stream continues to play

使用 Chromium 版本的 Edge:93.0.961.38

我正在用 React 构建一个音乐播放器应用程序。当用户按下要播放的 select 按钮时,它将通过呈现具有自动播放属性集和子 [=13] 的 <audio> 控件来自动播放 MP3 URL =] 元素与指定的 URL.

从无播放过渡到第一个 selected 节目时一切正常。但我希望它的工作方式是,如果用户主动更改他收听的节目,它将自动播放新的 selected 节目。

我可以从控制台日志中看到,当按下另一个显示按钮时,<MediaPlayer> 元素肯定会使用新 selected URL 重新呈现。我什至让它在组件本身中渲染 URL 。我可以在 F12 工具(DOM 检查器)中看到 <source> 元素上的 src 属性 肯定已更新。但是之前的节目一直在播放。

几乎足够好的解决方法是引入一个停止按钮,该按钮在没有任何 <audio> 控制的情况下重新呈现。然后按下另一个节目的按钮肯定会播放。

在下面的示例代码中,单击“环境”开始第一个节目。然后在开始播放后,单击“重金属”按钮。 “环境”音乐一直在播放。单击“停止”,然后再次按“重金属”——您将听到另一个节目。

有解决办法吗?或者我应该放弃使用内置音频 DOM 控件并使用 new Audio with state?

import './App.css';
import {useState, createContext, useContext, useEffect, useMemo} from 'react';

const AMBIENT = "https://www.selbie.com/samples/atmospherics.mp3";
const METAL   = "https://www.selbie.com/samples/wrekage.mp3";

const MediaPlayer = (props) => {

  if (props.src) {
    console.log("Url selected for playback: ", props.src);
  }
  else {
    console.log("Nothing ready to play");
  }

  return (props.src ? (<div><audio controls autoPlay><source src={props.src} /></audio><br/>{props.src}</div>)
                    : (<div>Nothing yet to play</div>)
         );
};

function App() {

  const [show, setShow] = useState(null);

  return (
    <div>
      <MediaPlayer src={show}/>
      <p></p>
      <button onClick={()=>setShow(AMBIENT)}>{"\u25B6\uFE0F Ambient"}</button><br/>
      <button onClick={()=>setShow(METAL)}>{"\u25B6\uFE0F Heavy Metal"}</button><br/>
      <button onClick={()=>setShow(null)}>{"\u23F9\uFE0F Stop"}</button><br/>
    </div>
  );

}

export default App;



根据 DBS 的评论,.load() 需要在更改源后对音频元素调用。这很容易通过 useEffect 完成,并在 useRef 的帮助下访问 <audio> 元素。

将 MediaPlayer 组件更新为:

const MediaPlayer = (props) => {

  const audioRef = useRef();  // ADDED THIS

  if (props.src) {
    console.log("Url selected for playback: ", props.src);
  }
  else {
    console.log("Nothing ready to play");
  }

  // ADDED useEffect
  useEffect(()=> {
    console.log("useEffect invoked");
    if (props.src) {
      let audio = audioRef.current;
      if (audio) {
        audio.load();
      }
    }
  }, [props.src]);

  // ADDED ref={audioRef} as attribute
  return (props.src ? (<div><audio ref={audioRef} controls autoPlay><source src={props.src} /></audio><br/>{props.src}</div>)
                    : (<div>Nothing yet to play</div>)
         );
};