Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  11 1292
Hei Folkens.


Jeg holder på å setter opp en liten spilleliste på en nettside og skal da i tillegg vise varigheten av alle sangene.

Oppsettet er veldig simpelt satt opp nå og vil bli forbedret. Trenger bare litt tips i forhold til JavaScripten her.

HTML:

Kode

<div class="song">
    <div class="duration-bar"></div>
    <div class="song-info">
        <div class="song_title" onCLick="play(<?php echo $song ?>)">
	<h4><?php the_title(); ?></h4>
    </div>

    <h6 class="song-duration" id="dur-<?php echo $song; ?>"></h6>

    <audio class="audio" id="audio-<?php echo $song; ?>" src="<?php echo get_field('music')['url']; ?>"></audio>
    </div>
</div>

javascript:

Kode

function play(i) {
	audio.forEach(function(audio) {
		audio.parentElement.classList.remove('playing');
		audio.pause();
		audio.currentTime = 0;
	});


	var target = document.querySelector('audio[id="audio-' + i + '"]');
	if(!target) return false;
	target.play();
	target.parentElement.classList.add('playing');
};

var audio = document.querySelectorAll('.audio');

for(var i = 0; i < audio.length; i++) {

	var playing = document.querySelector('.playing');

	audio[i].onplay = function() {
		if(playing) {
			this.pause();
			audio.currentTime = 0;
			playing.classList.remove('playing');
		}

		this.parentElement.classList.add('playing');
	}

	audio[i].addEventListener('ended', function() {
		this.parentElement.classList.remove('playing');
	});
}


Så da igjen er mitt spørsmål. Hvor i JavaScripten og hvordan kan jeg hente ut varigheten? Regner med det kanskje er f.eks:

Kode

audio.duration
en plass i koden der som trengs, men hvor?

Ingen som har noen tips?
Sist endret av Nikon01; 31. oktober 2019 kl. 20:51. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Hei viarlo, og takk for svar.

Når jeg bruker .duration får jeg bare NaN. Dette leste jeg at man får hvis den ikke klarer å hente ut varigheten av filen.
Kjedelig Streiting™
Realist1's Avatar
Har du prøvd noen av løsningene på topptreffene på Google? [1] [2]
Preload metadata og sett en eventhandler.
Hei.

Ja har prøvd dette. Jeg tror kanskje JavaScripten prøver å kjøre før selve filene er lastet inn.
Filene lastes inn ved hjelp av php og ACF i Wordpress.
JavaScripten ligger inline.

Tror dere det kanskje hjelper om jeg kjører JavaScripten i egen fil, eller om jeg evt kjører hele funksjonen på en delay?
Limited edition
Moff's Avatar
Som Realist1 skrev rett ovenfor, det er korrekt at skriptet kjører før informasjonen er tilgjengelig. Det er nettopp derfor han sier at du må bruke en eventhandler, som sørger for at koden kjører når preload-eventen trigges og informasjonen er tilgjengelig. Legg til

Kode

preload="metadata"
i som en attributt på <audio>-objektet ditt, slik at du ber om å laste inn metadata for filene. Deretter registrerer du en eventhandler som lytter på loadmetadata-eventen:

Kode

audio.onloadedmetadata = function() {

};
Her er et komplett eksempel:

Kode

<audio controls preload="metadata">
	<source src="bra_låt.mp3" type="audio/mp3">
</audio>

<script>
	var audio = document.getElementsByTagName("audio");
	
	for(var i = 0; i < audio.length; i++) {
		(function(a) {
			a.onloadedmetadata = function() {
				// a.duration inneholder lengden i sekunder
				var seconds = Math.floor(a.duration % 60);
				var minutes = Math.floor((a.duration % 3600) / 60);
				
				// Legg til leading zeroes, hvis du vil ("3:2" -> "03:02")
				var duration = (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
				
				console.log(duration); // Do stuffs
			};
		})(audio[i]);
	}
</script>
Takk for alle svar.

Jeg prøvde meg på en eventhandler i sta, men fikk ikke denne helt til å fungere som jeg ville.

Men jeg løste det med en timeout siden jeg så at dere snakket om at en event handler som lytter på loadmetadata skal fungere, så burde også en timeout på 1sek også fungere.


Så nå får jeg vist riktig tidspunkt. Men nå skal jeg vise data fra denne til en annen.


SÅ det jeg har nå:

Kode

<h6 class="song-duration" id="dur-<?php echo $song; ?>"></h6>

<audio class="audio" id="audio-<?php echo $song; ?>" src="<?php echo get_field('music')['url']; ?>"></audio>
Her har jeg en h6 med ID'en dur-1, dur-2, dur-3 etc ut ifra hvor mange lydfiler jeg har.

Det samme har jeg med audio, bare at den er audio-1, audio-2 osv.

Jeg må her loope igjennom Audio som jeg har gjort, men skal da vise duration inne i H6 her.

Som dere vet er jeg ganske fersk i JavaScript, men lærer stadig. Så da lurer jeg på om jeg her kan loope igjennom Audio, hente duration for så å targete nextSibling og finne "dur-" ID'en eller må jeg kjøre en for loop i en for loop ?
Limited edition
Moff's Avatar
Grunnen til at du ikke skal bruke en timer, særlig ikke på så lite som ett sekund, er at dette feiler når musikken bruker mer enn ett sekund på å lastes ned. Det vil være svært problematisk for mobilbrukere over 4G, folk som sitter på dårlig tog- og/eller fly-wifi og slike ting. Det går sikkert bra for de av oss som har fiber - men du bør bruke en eventhandler, fordi den er designet for å kjøre koden når eventen skjer (altså når metadata er tilgjengelig).

Hvis du ser på koden jeg postet ovenfor, så bruker jeg getElementsByTagName for å hente alle <audio>-objekter i hele dokumentet. Jeg går gjennom hvert enkelt objekt med en for-loop. Det som skjer på innsiden av for-loopen er en såkalt IIFE (Immediately Invoked Function Expression). Fordi koden inne i eventhandleren er async (den kjører ikke i takt med resten av skriptet, den venter på signal), så kan jeg ikke referere til audio[i], fordi verdien av både audio og i-variabelen kan være endret når eventhandler-koden kjøres. En IIFE "låser" tilstanden til variablene, slik at jeg kan referere til dem på det tidspunktet IIFE-en ble kjørt. Dette fungerer fordi JavaScript har såkalt function-scope, men det er et litt avansert tema som tar tid å forklare. Det som i praksis skjer er at jeg mater inn hver enkelt <audio> i variabelen "a" som sendes til eventhandleren. Den vil da vente til metadata er tilgjengelig for hvert enkelt <audio>-objekt, og deretter behandle a.duration, som er lengden på sangen i sekunder.

Linjen hvor jeg skriver console.log er der du kan legge inn logikk for hva du ønsker å gjøre med informasjonen. Hvis du vil oppdatere et heading-objekt, så kan du for eksempel legge inn en ID-referanse i audio-objektet som peker til riktig heading:

Kode

<h1>Bra låt (<span id="track-1"></span>)</h1>

<audio controls preload="metadata" data-header-id="track-1">
	<source src="bra_låt.mp3" type="audio/mp3">
</audio>

<h1>Fet låt (<span id="track-2"></span>)</h1>

<audio controls preload="metadata" data-header-id="track-2">
	<source src="fet_låt.mp3" type="audio/mp3">
</audio>

<h1>Chill låt (<span id="track-3"></span>)</h1>

<audio controls preload="metadata" data-header-id="track-3">
	<source src="chill_låt.mp3" type="audio/mp3">
</audio>

<script>
	var audio = document.getElementsByTagName("audio");
	
	for(var i = 0; i < audio.length; i++) {
		(function(a) {
			a.onloadedmetadata = function() {
				// Hent ID fra audio-objektet
				var id = a.getAttribute("data-header-id");
				
				// a.duration inneholder lengden i sekunder
				var seconds = Math.floor(a.duration % 60);
				var minutes = Math.floor((a.duration % 3600) / 60);
				
				// Legg til leading zeroes, hvis du vil ("3:2" -> "03:02")
				var duration = (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
				
				// Skriv duration til heading-objektet
				document.getElementById(id).innerHTML = duration;
			};
		})(audio[i]);
	}
</script>
PHP-skriptet ditt må her sørge for å generere <h1>-objekter som inneholder en eller annen referanse (for eksempel en ID), og denne må samsvare med data-header-id-attributten på <audio>-objektene. Det er ingen fasit på hva som er beste løsning på denne problemstillingen. Du kan også få PHP-koden din til å lage en heading, et audio-objekt og en eventhandler for hver enkelt sang om du vil. Det er ikke like smooth, men det fungerer det også.
Takker så meget Moff.
Da ser det faktisk ut som jeg kanskje ble litt klokere.

Skal studere koden og prøve å få dette inn i nøtta ila helga her.

Hei igjen.

Siden vi er så godt inni hele pakka her nå da.

Spille av lyd:

Kode

function play(i) {
	var target = document.querySelector('audio[id="audio-' + i + '"]');
	if(!target) return false;
	target.play();
	target.parentElement.classList.add('playing');
};

var audio = document.querySelectorAll('.audio');

HTML:

Kode

<div onCLick="play(<?php echo $song ?>)" class="pausePlay" id="pause-<?php echo $song; ?>" >
	<audio data-playing="pause-<?php echo $song; ?>" data-header-id="dur-<?php echo $song; ?>" class="audio" id="audio-<?php echo $song; ?>" src="<?php echo get_field('music')['url']; ?>"></audio>
</div>

I DIV elementet her nå har jeg bakgrunnsbilde for en play knapp. Det samme for pause. Pause knappen kommer fram når denne får klassen "playing".

Men jeg får ikke til å pause lyden?
Har prøvd flere forskjellige metoder funnet på nett, men ser ikke hvorfor dette ikke vil fungere.

Det jeg har prøvd er å sjekke klassen "playing" og sjekke om childen audio har duration > 0 og deretter sette audio til pause().

Noen tips her folkens?
Sist endret av Nikon01; 2. november 2019 kl. 23:01. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Limited edition
Moff's Avatar
Det er ikke så rart at du ikke får til å pause sangen, du har ingen kode som gjør dette. Det er ikke snakk om at koden ikke virker, du har rett og slett ikke skrevet kode som stopper sanger. (Ut i fra det jeg kan se, anyway.)

Funksjonen for å stoppe eller pause en lyd er "pause()". Denne funksjonen ser jeg ikke noe sted her.

Her er et eksempel på hvordan play/pause og låtvalg kan løses:

Kode

<style>
	.track {
		cursor: pointer; /* "pointer" gir en musepeker som sier at brukeren kan trykke, litt som en link */
	}
</style>

<!-- Spilleliste -->
<span class="track" data-track-id="track-1">Fet låt</span><br>
<span class="track" data-track-id="track-2">Heftig låt</span><br>

<!-- Play/pause-knapp -->
<button id="playButton">Spill av</button>

<!-- Lydobjekter -->
<audio data-track-id="track-1">
	<source src="fet_låt.mp3" type="audio/mp3">
</audio>
<audio data-track-id="track-2">
	<source src="heftig_låt.mp3" type="audio/mp3">
</audio>

<script>
	var currentTrack = undefined; // Placeholder for sangen som spilles av i øyeblikket
	
	var button = document.getElementById("playButton"); // Play/Pause-knapp
	var tracks = document.querySelectorAll(".track[data-track-id]"); // Alle objekter med klassen "track" og attributten "data-track-id"
	
	for(var i = 0; i < tracks.length; i++) { // For hver låt i spillelisten (hver <span> i praksis)
		tracks[i].addEventListener("click", function() { // Eventlistener for museklikk
			// Hent <audio>-elementet med samme data-track-id som elementet i spillelisten
			var audio = document.querySelector("audio[data-track-id='" + this.getAttribute("data-track-id") + "']");
			
			if(audio !== undefined) { // Sjekk at vi fant et samsvarende <audio>-element
				if(currentTrack !== undefined) { // Spiller vi av en låt fra før?
					currentTrack.pause(); // Stopp låten som spilles av nå
				}
				
				currentTrack = audio; // Endre valgt låt
				currentTrack.currentTime = 0; // Reset trackbar til 0 (start låten forfra)
				currentTrack.play(); // Spill av
				
				button.innerHTML = "Pause"; // Oppdater play/pause-knapp
			}
		});
	}
	
	// Funksjon for å starte og stoppe låter med play/pause-knapp
	button.addEventListener("click", function() { // Lytt til museklikk
		if(currentTrack === undefined) {
			return; // Ingen låt er valgt, ikke gjør noe
		}
		
		if(currentTrack.paused) { // Sang er på pause
			this.innerHTML = "Pause"; // Endre tekst på knapp
			currentTrack.play(); // Gjenoppta avspilling
		} else {
			this.innerHTML = "Spill av"; // Endre tekst på knapp
			currentTrack.pause(); // Pause låt
		}
	});
</script>
Hei Moff.

Det er fordi jeg har tatt bort alt jeg har prøvd

Sånn ut ifra koden jeg har nå, så kjører jeg audio via target og går etter audio elementet med en ID.

Her har jeg da prøvd å kjøre f.eks:

Kode

var target = document.querySelector('audio[id="audio-' + i + '"]');
	if(!target) return false;
	if(target.paused) {
		target.play();
		target.parentElement.classList.add('playing');
		console.log(target);
	} else {
		target.pause();
                target.parentElement.classList.remove('playing');
	}
Når jeg trykker på knappen så spilles lydfilen av, og når jeg trykker igjen, så starter den bare på nytt.


Denne har jeg også prøvd, som fungerer på en annen side, men ikke her:

Kode

var audio = document.querySelectorAll('.audio');

for(var i = 0; i < audio.length; i++) {

	var playing = document.querySelector('.playing');

	audio[i].onplay = function() {
		if(this.parentElement.classList.contains('playing')) {
			this.stop();
			audio.currentTime = 0;
			document.querySelector('.playing').classList.remove('playing');
		}

		this.parentElement.classList.add('playing');
	}


	audio[i].addEventListener('ended', function() {
		this.parentElement.classList.remove('playing');
	});
}
Limited edition
Moff's Avatar
Sitat av Nikon01 Vis innlegg
Det er fordi jeg har tatt bort alt jeg har prøvd
Vis hele sitatet...
Og hvordan i alle dager skal vi vite det? Når du sier at noe i koden din ikke virker, og du poster kode, da bør det ikke komme som noen overraskelse at vi går ut i fra at det er den koden du snakker om.

Problemet ditt oppstår fordi du ber sangen om å starte på nytt i "onplay"-eventen, og denne trigger både når sangen starter forfra og gjenopptas etter pause. Linjen som inneholder "audio.currentTime = 0;" må vekk.

Er også rimelig sikker på at stop() ikke er en gyldig funksjon for å stoppe lyd, i alle fall ikke i alle nettlesere. Hvis du ser på eksempelet jeg postet ovenfor så bruker jeg pause() i stedet, og setter kun currentTime til 0 når brukeren velger en ny låt.