11525 sujets

JavaScript, DOM et API Web HTML5

Bonjour,
Je souhaite pouvoir cliquer sur différentes Div contenant chacune un lien audio et, au clic de la souris, lire l'audio dans un lecteur audio (toujours le même).
<body>
  <audio id="lecteur_audio" controls="controls">audio inconnu</audio>

  <ul>
    <li class="piste_audio" href="/audios/03-flamenco.mp3">flamenco</li>
    <li class="piste_audio" href="/audios/11-bwv847-bosendorfer.mp3">Bach</li>
    <li class="piste_audio" href="/audios/04-rencontre.mp3">Rencontre</li>
  </ul>

    <script src="/moment_musical/test.js"></script>
</body>

var lecteur = document.getElementById('lecteur_audio');
var pistes = document.querySelectorAll('.piste_audio');

for (var i=0; i < pistes.length; i++ ) {
   var lien = pistes[i].getAttribute('href');
   pistes[i].addEventListener('click',() =>
   lecteur.setAttribute('src',lien));
   lecteur.play();
}

ce que je constate
C'est seul le dernier lien de ma boucle for qui est pris en compte.
ce que j'aimerais
C'est pourvoir switcher entre les différents liens.

Vous l'aurez compris, je suis très débutant dans le javascript !
Merci par avance pour votre aide.
Bonjour,

C'est le piège classique de var.

Si tu n'as pas d'obligation de compatibilité avec de trop anciens navigateurs (dont Internet Explorer), remplace var par let et ça fonctionnera.

Sinon, en effet, avec ton code actuel, quelque soit le lien cliqué, ce sera toujours le dernier qui sera chargé.


Pour en savoir plus sur var/let, je t'invite à faire une recherche.
Merci Quentin,
je comprends qu'il s'agit d'un problème de portée de la variable. Ce n'est pas très clair encore dans mon esprit mais avec le code suivant, ça fonctionne du coup très bien !
var pistes = document.querySelectorAll('.piste_audio');

for (var i=0; i < pistes.length; i++ ) {
    let lecteur = document.getElementById('lecteur_audio');
    let lien = pistes[i].getAttribute('href');
    pistes[i].addEventListener('click',() => {
    lecteur.setAttribute('src',lien);
    lecteur.play();
});
}


Est-ce qu'il y a une manière plus "élégante" ou plus limpide pour arriver au même résultat ?
Salut,

Pour "simplifier" (faut le dire vite vu que c'est pas tellement plus lisible au final j'ai l'impression ..), tu dois pouvoir faire directement une boucle foreach plutôt que de faire une variable puis une boucle for dessus.

Et après tu dois pouvoir utiliser directement l'event pour voir ce qui est cliqué et éviter ton problème de variable (pour le coup je trouve plus intuitif mais pareil pas tellement plus lisible que la boucle for)


var lecteur = document.getElementById('lecteur_audio');

document.querySelectorAll(".piste_audio").forEach( mp3 => { 
    mp3.addEventListener('click', event => {
        lecteur.setAttribute('src',event.target.getAttribute('href'));
        lecteur.play();
  })
});


Edit : avec le jsfiddle https://jsfiddle.net/07m8dpau/1/

Edit 2 pour l'explication (en anglais) let vs var : https://stackoverflow.com/questions/30899612/explanation-of-let-and-block-scoping-with-for-loops
Modifié par Mathieuu (24 Feb 2022 - 10:54)
Merci Mathieuu pour cette suggestion. Le foreach est je trouve également plus intuitif.

Nouveau problème de cible : cette fois-ci je veux indiquer le temps restant de l'audio à côté du lien cliqué. Seulement, cela se déclenche à côté de tous les liens :

https://codepen.io/MiKL78/pen/wvPOazO


<audio id="lecteur_audio" controls="controls">audio inconnu</audio>

<li class="pistes_audio" data-href="https://lasonotheque.org/museumofsounds/1_1.mp3">son1 duree : <span class="duree"></span></li>
<li class="pistes_audio" data-href="https://lasonotheque.org/museumofsounds/10_1.mp3">Son2 duree : <span class="duree"></span></li>
<li class="pistes_audio" data-href="https://lasonotheque.org/museumofsounds/5_1.mp3">Son3 duree : <span class="duree"></span></li>


let lecteur_audio = document.getElementById('lecteur_audio');
let liens_audio = document.querySelectorAll('.pistes_audio');
let duree = document.querySelectorAll('.duree');
let total;
let temps;


function lire_audio() {
    for(let i=0; i<liens_audio.length; i++){
        let lien_audio = liens_audio[i].dataset.href;
        
        liens_audio[i].addEventListener('click', () => {
            lecteur_audio.setAttribute('src', lien_audio);
            lecteur_audio.setAttribute('preload', 'metadata');
            lecteur_audio.play();
        })
            
        lecteur_audio.addEventListener('loadedmetadata', () => {
            total = parseInt(lecteur_audio.duration);
        })

        lecteur_audio.addEventListener('timeupdate', () => {
        temps = parseInt(lecteur_audio.currentTime);
        duree[i].innerHTML = total - temps;
        });

    }
}
lire_audio()
Modérateur
Bonjour,

tu ne vérifie pas quel lien est cliqué.
Tu peut essayer d'alimenter une variable supplementaire pour la comparer et accéder au seul span.duree que tu veut mettre à jour.

Exemple en utilisant la variable playing alimentée avec le numéro d'index du lien_audio cliquer.
let lecteur_audio = document.getElementById('lecteur_audio');
let liens_audio = document.querySelectorAll('.pistes_audio');
let duree = document.querySelectorAll('.duree');
let total;
let playing = 0;
function lire_audio() {
    for(let i=0; i<liens_audio.length; i++){
        let lien_audio = liens_audio[i].dataset.href;
        liens_audio[i].addEventListener('click', () => {
            lecteur_audio.setAttribute('src', lien_audio);
            lecteur_audio.setAttribute('preload', 'metadata');
            lecteur_audio.play();
            playing = i ;
        })
            
        lecteur_audio.addEventListener('loadedmetadata', () => {
            total = parseInt(lecteur_audio.duration);
        })

        lecteur_audio.addEventListener('timeupdate', () => {
         let temps = parseInt(lecteur_audio.currentTime);
          if(i === playing ) {
         duree[i].innerHTML = total - temps;     
          }
        });

    }
}
lire_audio()
possible
Merci gcyrillus, ça marche impec !
Lorsque je clique d'un lien à un autre, la durée s'affiche bien à côté du lien cliqué mais les données restent à côté des liens anciennement cliqués.
Du coup faire en sorte d'effacer les données des autres span.duree lorsque je clique sur un nouveau lien ?
Modérateur
Tu peut te servir de else et vider tes span qui ne correspondent pas à la condition
if(i === playing ) {
         duree[i].innerHTML = total - temps;     
          }
          else {
         duree[i].innerHTML = '';     
          }
          


tu peut aussi les laisser et reprendre la lecture précédente la ou elle en etait https://codepen.io/gc-nomade/pen/KKyEzYM?editors=0010 (je pensais que cela serait probablement ta prochaine question Smiley cligne , trompé! )
Ouah, trop bien ! Merci.
a écrit :

(je pensais que cela serait probablement ta prochaine question Smiley cligne , trompé! )

C'est cool d'avoir des réponses avant même d'avoir conscience de la question ! Smiley biggrin
C'est pas perdu, ça me permet de mieux comprendre le JS et ça va me servir pour une autre configuration.