暂停所有音频,然后仅恢复正在播放的音频

问题描述 投票:0回答:1

嗨:)我正在尝试制作一个应用程序,其中有几个环境声音音频。我想添加的一项功能是,当我单击复选框时,所有正在播放的音频都将停止,而当我取消选中该复选框时,只有在选中之前正在播放的音频才会恢复。

我正在使用 React 和 Redux。这就是我拥有的。

import "./styles.css";
import { useRef, useReducer } from "react";

const audioActionType = {
  TOGGLE_PLAY: "TOGGLE_PLAY",
  SET_VOLUME: "SET_VOLUME",
  TOGGLE_ALL_PAUSED: "TOGGLE_ALL_PAUSED",
};

const initialAudioState = {
  audios: [
    {
      playing: false,
      id: 1,
      volume: 25,
      title: "Coffe making",
      src: "..//audio/espresso-machine.mp3",
    },
    {
      playing: false,
      id: 2,
      volume: 25,
      title: "Coffe machine",
      src: "..//audio/espresso-machine.mp3",
    },
  ],
  allPaused: false,
};

function AudioReducer(stateAudios, actionAudios) {
  switch (actionAudios.type) {
    case audioActionType.TOGGLE_PLAY:
      return {
        ...stateAudios,
        audios: stateAudios.audios.map((audio) =>
          audio.id === actionAudios.id
            ? { ...audio, playing: !audio.playing }
            : audio
        ),
      };
    case audioActionType.SET_VOLUME:
      return {
        ...stateAudios,
        audios: stateAudios.audios.map((audio) =>
          audio.id === actionAudios.id
            ? { ...audio, volume: actionAudios.volume }
            : audio
        ),
      };
    case audioActionType.TOGGLE_ALL_PAUSED:
      const anyAudioPlaying = { ...stateAudios.audios };
      console.log(anyAudioPlaying);
      if (stateAudios.allPaused) {
        return {
          ...stateAudios,
          audios: stateAudios.audios.map((audio) => ({
            ...audio,
            playing: false,
          })),
          allPaused: false,
        };
    default:
      return stateAudios;
  }
}

export default function App() {
  const [state, dispatch] = useReducer(AudioReducer, initialAudioState);

  const audioRefs = useRef(
    //creaamos una referencia para los audios para poder pausarlos, cambiar el volumen, etc
    state.audios.reduce((acc, audio) => {
      //con reduce recorremos el array de audios y creamos un objeto que almacena todos los aduios con el acc (contador) como el id del audio y su valor como el src del audio. quedaria algo así: {1: src1.mp3, 2:src2.mp3}
      acc[audio.id] = new Audio(audio.src);
      return acc;
    }, {})
  ).current; //el current lo ponemos aquí para no tener que usarlo cada vez que queramos acceder al valor del Ref

  const togglePlay = (id) => {
    dispatch({ type: "TOGGLE_PLAY", id });
    const audio = audioRefs[id];
    state.audios.find((audio) => audio.id === id).playing
      ? audio.pause()
      : audio.play();
  };

  const setVolume = (id, volume) => {
    dispatch({ type: "SET_VOLUME", id, volume });
    audioRefs[id].volume = volume / 100;
  };

  console.log(state);

  return (
    <div id="sounds-section" className="sections">
      <input
        type="checkbox"
        id="pause"
        name="pause"
        checked={state.allPaused}
        onChange={() => dispatch({ type: "TOGGLE_ALL_PAUSED" })}
      />
      <label htmlFor="pause"> Pause all</label>
      <div id="sounds">
        {state.audios.map((audio) => (
          <div className="sound" key={audio.id}>
            <div>
              <button
                onClick={() => togglePlay(audio.id)} //es importante poner el () porque sinó estamos llamando a la función cuando se crea el objeto y no cuando clicamos en el botón
                dangerouslySetInnerHTML={{
                  __html: audio.playing ? "&#x23F8;" : "&#x25B6;",
                }}
              />
              <h4>{audio.title}</h4>
            </div>
            {audio.playing && (
              <input
                className="volume"
                type="range"
                min="0"
                max="100"
                step="1"
                value={audio.volume}
                onChange={(e) => {
                  setVolume(audio.id, e.target.value);
                }}
              />
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

我在 allPaused 将所有播放属性转换为 false 之前无法查看之前的状态。

javascript reactjs react-hooks
1个回答
0
投票

也许在

audioActionType.TOGGLE_ALL_PAUSED
减速器情况下,您只切换
allPaused
状态并像您一样处理 UI 中的播放,但进行修改以考虑
allPaused
状态。当
allPaused
状态再次切换时,您仍然会拥有正在播放的内容的任何现有状态,因为它从未更新过。

音频减速器

function AudioReducer(stateAudios, actionAudios) {
  switch (actionAudios.type) {
    case audioActionType.TOGGLE_PLAY:
      return {
        ...stateAudios,
        audios: stateAudios.audios.map((audio) =>
          audio.id === actionAudios.id
            ? { ...audio, playing: !audio.playing }
            : audio
        ),
      };

    case audioActionType.SET_VOLUME:
      return {
        ...stateAudios,
        audios: stateAudios.audios.map((audio) =>
          audio.id === actionAudios.id
            ? { ...audio, volume: actionAudios.volume }
            : audio
        ),
      };

    case audioActionType.TOGGLE_ALL_PAUSED:
      return {
        ...stateAudios,
        allPaused: !stateAudios.allPaused,
      };

    default:
      return stateAudios;
  }
}

应用程序

export default function App() {
  const [state, dispatch] = useReducer(AudioReducer, initialAudioState);

  const audioRefs = useRef(
    state.audios.reduce((acc, audio) => {
      acc[audio.id] = new Audio(audio.src);
      return acc;
    }, {})
  ).current;

  const togglePlay = (id) => {
    dispatch({ type: "TOGGLE_PLAY", id });
    const audio = audioRefs[id];
    state.audios.find((audio) => audio.id === id).playing
      ? audio.pause()
      : audio.play();
  };

  const setVolume = (id, volume) => {
    dispatch({ type: "SET_VOLUME", id, volume });
    audioRefs[id].volume = volume / 100;
  };

  const toggleAllPaused = () => {
    dispatch({ type: "TOGGLE_ALL_PAUSED" });

    state.audios.forEach(audio => {
      // If all audios are currently paused
      if (state.allPaused) {
        // And the current audio was previously playing, play audio
        if (audio.playing) {
          audio.play();
        }
      // Else just pause all the adios
      } else {
        audio.pause();
      }
    });
  };

  return (
    <div id="sounds-section" className="sections">
      <input
        type="checkbox"
        id="pause"
        name="pause"
        checked={state.allPaused}
        onChange={toggleAllPaused}
      />
      <label htmlFor="pause"> Pause all</label>
      <div id="sounds">
        {state.audios.map((audio) => (
          <div className="sound" key={audio.id}>
            <div>
              <button
                onClick={() => togglePlay(audio.id)}
                dangerouslySetInnerHTML={{
                  __html: audio.playing ? "&#x23F8;" : "&#x25B6;",
                }}
              />
              <h4>{audio.title}</h4>
            </div>
            {audio.playing && (
              <input
                className="volume"
                type="range"
                min="0"
                max="100"
                step="1"
                value={audio.volume}
                onChange={(e) => {
                  setVolume(audio.id, e.target.value);
                }}
              />
            )}
          </div>
        ))}
      </div>
    </div>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.