Home > database >  How to build a button to click on and play / stop an audio?
How to build a button to click on and play / stop an audio?

Time:02-23

i want to build a image button, that plays an audio. My Version works but when I want to use it more than once on a site, it only play one mp3, not the other ones.

My Code:

<audio loop="false" src="audio_01.mp3">&nbsp;</audio>

<p><img alt=""  src="image.png" style="width: 40%;cursor:pointer" /></p>
<script>
  var aud = document.getElementById("ASong").children[0];
  var isPlaying = false;
  aud.pause();

  function playPause() {
    if (isPlaying) {
      aud.pause();
    } else {
      aud.play();
    }
    isPlaying = !isPlaying;
  }
</script></div>

and

<div id="BSong" onclick="playPause()" type="button">
<audio loop="false" src="audio_02.mp3">&nbsp;</audio>

<p><img alt=""  src="image.png" style="width: 40%;cursor:pointer" /></p>
<script>
  var aud = document.getElementById("BSong").children[0];
  var isPlaying = false;
  aud.pause();

  function playPause() {
    if (isPlaying) {
      aud.pause();
    } else {
      aud.play();
    }
    isPlaying = !isPlaying;
  }
</script></div>

So you have an idea what the problem is that the button only play one of them on the website?

CodePudding user response:

You are using the same variable names multiple times like aud, isPlayig, etc..

To solve this issue, you should declare only once the whole script and form the onclick="playPause()" send the id of the song you want to play.

Be aware if there is already some music which is playing.

CodePudding user response:

It's hard to tell how your two current code snippets are arranged with respect to each other, but duplicating the code over and over every time you want to add another track is going to be unmaintainable. As it stands, the variables for isPlaying and aud probably overwrite each other, depending on how they're laid out, even if they're in different scripts. Using const or let instead of var and use strict; at the top of your script can help detect these aliases.

You could add closures around each one to keep them distinct, but a better approach is to write a loop (which also acts as a scoping closure) and dynamically add the listener to each element. For example:

const trackEls = [...document.querySelectorAll(".track")];

for (const trackEl of trackEls) {
  const audioEl = trackEl.querySelector("audio");
  trackEl.addEventListener("click", () => {
    audioEl.paused ? audioEl.play() : audioEl.pause();
  });
}
<div >
  <div type="button" >
    <audio src="https://upload.wikimedia.org/wikipedia/commons/d/d8/Bourne_woods_2020-11-18_0732.mp3"></audio>
    <img alt="play track icon" src="http://placekitten.com/50/50" >
  </div>
  <div type="button" >
    <audio src="https://upload.wikimedia.org/wikipedia/commons/e/ea/Rapid-Acoustic-Survey-for-Biodiversity-Appraisal-pone.0004065.s017.ogg"></audio>
    <img alt="play track icon" src="http://placekitten.com/50/50" >
  </div>
</div>

Note that the above code lets multiple audio files play at once. If you want to stop all other audio elements when a new one is clicked and reset their time, you can do that with a loop or an extra variable that keeps track of the currently-playing track. For example:

const trackEls = [...document.querySelectorAll(".track")];
let currentTrack;

for (const trackEl of trackEls) {
  const audioEl = trackEl.querySelector("audio");
  trackEl.addEventListener("click", () => {
    if (audioEl !== currentTrack) {
      if (currentTrack) {
        currentTrack.pause();
        currentTrack.currentTime = 0;
      }

      currentTrack = audioEl;
    }

    audioEl.paused ? audioEl.play() : audioEl.pause();
  });  
}
<div >
  <div type="button" >
    <audio src="https://upload.wikimedia.org/wikipedia/commons/d/d8/Bourne_woods_2020-11-18_0732.mp3"></audio>
    <img alt="play track icon" src="http://placekitten.com/50/50" >
  </div>
  <div type="button" >
    <audio src="https://upload.wikimedia.org/wikipedia/commons/e/ea/Rapid-Acoustic-Survey-for-Biodiversity-Appraisal-pone.0004065.s017.ogg"></audio>
    <img alt="play track icon" src="http://placekitten.com/50/50" >
  </div>
</div>

A few remarks on your code:

  • There's no need for isPlaying variables since audio elements already track their playing/paused state with audioElement.paused. If you track it in external state, you add further complication and room for bugs if your variable and the the audio element's state go out of sync.
  • Avoid putting a <script> in a <div>. <script> is usually a child of <body> or <head> (probably <body> in this case), after all of the HTML tags are closed.
  • onclick on an HTML element is generally poor practice. HTML should be structural, not behavioral. Similarly, style="width: 40%;cursor:pointer" should be moved to an external stylesheet and applied to a class.
  • .children[0]; is a brittle way to select the audio element in a track. If you wind up rearranging elements in the div, this code is liable to break. document.querySelector("#BSong audio") is more precise and robust to refactors, although using classes instead of ids enables easier dynamism so you don't have to type each track out by hand.
  • CSS classes are usually kebab-case, so hover_pic would be hover-pic.
  • Related