Consultando os controles do jogador
O que é um player personalizado sem controles personalizados? A próxima etapa é consultar todos os controles personalizados que adicionamos ao HTML. Nós vamos usar o Document.querySelector()
método para retornar cada elemento associado atribuído por uma variável.
// Player controls and attributes const playButton = document.querySelector(".player-play-btn") const playIcon = playButton.querySelector(".player-icon-play") const pauseIcon = playButton.querySelector(".player-icon-pause") const progress = document.querySelector(".player-progress") const progressFilled = document.querySelector(".player-progress-filled") const playerCurrentTime = document.querySelector(".player-time-current") const playerDuration = document.querySelector(".player-time-duration") const volumeControl = document.querySelector(".player-volume")
Aqui temos variáveis para cada controle independente e a barra de progresso mostrada na interface do usuário.
Esperando antes que o JavaScript dispare
Para carregar corretamente o áudio, que às vezes pode demorar mais do que outros itens na página, provavelmente faz sentido esperar que a página inteira carregue antes de executar qualquer JavaScript.
Começaremos com um ouvinte de evento que aguarda o carregamento da página. Podemos agrupar todo o nosso código neste bloco.
window.addEventListener("load", () => { // all code goes here besides variables })
Começaremos ouvindo o playButton
evento de clique da variável para instruir nosso jogador a Toque.
// Play button toggle playButton.addEventListener("click", () => { // check if context is in suspended state (autoplay policy) // By default, browsers won't allow you to autoplay audio. // You can override by finding the AudioContext state and resuming it after a user interaction like a "click" event. if (audioCtx.state === "suspended") { audioCtx.resume() } // Play or pause track depending on state if (playButton.dataset.playing === "false") { audioElement.play() playButton.dataset.playing = "true" playIcon.classList.add("hidden") pauseIcon.classList.remove("hidden") } else if (playButton.dataset.playing === "true") { audioElement.pause() playButton.dataset.playing = "false" pauseIcon.classList.add("hidden") playIcon.classList.remove("hidden") } })
Algumas coisas acontecem ao mesmo tempo quando o playButton
é clicado.
- Os navegadores são inteligentes o suficiente para impedir que o áudio de reprodução automática seja reproduzido no primeiro carregamento. Dentro de
AudioContext
método, há um método de estado que retorna um valor de “suspenso”, “em execução” ou “fechado”. No nosso caso, estaremos procurando por “suspenso”. Se for esse o estado que retorna, podemos prosseguir para retomar o áudio com o método chamadoresume()
. -
Usamos atributos de dados no HTML para indicar quando o botão está “reproduzindo” ou “pausado”.
-
Se o botão reproduzir ou pausar for clicado, podemos dizer dinamicamente ao
audioElement
para Toque ou pausa. -
Para uma melhor experiência do usuário, adicionei a capacidade de mostrar e ocultar os ícones de reprodução ou pausa, dependendo do estado do player.
Atualizar Carimbos de Hora e Progresso
Cada faixa que você carrega com um contexto AudioElement terá suas características e metadados que você pode exibir no HTML. Começamos zerando tudo no carregamento da primeira página e passamos a chamar uma função que atualiza e formata dinamicamente o tempo conforme o áudio é reproduzido ou pausado.
Além disso, mostraremos uma barra de progresso que será preenchida dinamicamente com base na quantidade de áudio decorrido. Isso é útil para o usuário final que pode querer dar uma olhada em uma barra de progresso em vez de ler o tempo restante.
// Update progress bar and time values as audio plays audioElement.addEventListener("timeupdate", () => { progressUpdate() setTimes() })
Criei duas funções que são extraídas em outro lugar no arquivo JavaScript. A principal coisa a denotar sobre o código acima é o tipo de ouvinte de evento que acompanhamos. o timeupdate
O evento é exclusivo para mídia como áudio ou vídeo na API da Web.
Exibição e formatação de hora
Podemos usar o playerCurrentTime
e playerDuration
variáveis para exibir e formatar a hora. Definiremos o textContent dessas tags no HTML para corresponder a um novo timestamp relativo aos atributos atuais do audioElement. Um audioElement terá um currentTime
propriedade e um duration
propriedade.
Usando a API de data em JavaScript, podemos acessar uma linha útil para converter os segundos padrão que são retornados de currentTime
e duration
em um formato que corresponda HH:MM:SS
(Horas, Minutos, Segundos).
// Display currentTime and duration properties in real-time function setTimes() { playerCurrentTime.textContent = new Date(audioElement.currentTime * 1000) .toISOString() .substr(11, 8) playerDuration.textContent = new Date(audioElement.duration * 1000) .toISOString() .substr(11, 8) }
Atualizando o progresso do jogador
Atualizar a barra de progresso em nosso HTML é relativamente simples e se resume a um cálculo de porcentagem. Obteremos a porcentagem retornada dividindo o audioElement.currentTime
pelo audioElement.duration
e multiplicando por 100.
Finalmente, podemos definir algum CSS via JavaScript usando o progressFilled
variável que criamos antes e ajustando o flex-basis
propriedade para aumentar ou diminuir, dependendo da porcentagem de alteração.
// Update player timeline progress visually function progressUpdate() { const percent = (audioElement.currentTime / audioElement.duration) * 100 progressFilled.style.flexBasis = `${percent}%` }
Adicionar controles de volume
Ajustar o volume retorna ao objeto AudioContext que usamos antes. Precisamos chamar um método chamado createGain()
e altere o valor de ganho para mapear a entrada do intervalo de volume no HTML.
// Bridge the gap between gainNode and AudioContext so we can manipulate volume (gain) const gainNode = audioCtx.createGain() volumeControl.addEventListener("change", () => { gainNode.gain.value = volumeControl.value }) track.connect(gainNode).connect(audioCtx.destination)
Nós criamos um track
variável no início deste tutorial e finalmente colocá-la em uso aqui. Usando o connect()
método, você pode conectar a pista para o gainNode
e depois para o AudioContext
. Sem esta linha, a entrada da faixa de volume não sabe sobre o volume do áudio.
Nós vamos ouvir por um mudança evento para mapear o volume em relação ao ganho.
O que acontece quando o áudio termina?
Podemos redefinir o player após o término do áudio, para que ele esteja pronto para outra audição, caso o usuário final queira recomeçar.
// if the track ends, reset the player audioElement.addEventListener("ended", () => { playButton.dataset.playing = "false" pauseIcon.classList.add("hidden") playIcon.classList.remove("hidden") progressFilled.style.flexBasis = "0%" audioElement.currentTime = 0 audioElement.duration = audioElement.duration })
Aqui, alternamos o ícone do botão de reprodução de pausa para Toquedefina o atributo de reprodução de dados como false
redefinir a barra de progresso e o audioElement’s currentTime
e duration
propriedades.
Esfregando a barra de progresso para pular e retroceder
Nossa barra de progresso é visualmente funcional, mas seria mais útil se você pudesse clicar em qualquer lugar na linha do tempo e ajustar a reprodução de áudio atual. Podemos conseguir isso com uma série de ouvintes de eventos e uma nova função.
// Scrub player timeline to skip forward and back on click for easier UX let mousedown = false function scrub(event) { const scrubTime = (event.offsetX / progress.offsetWidth) * audioElement.duration audioElement.currentTime = scrubTime } progress.addEventListener("click", scrub) progress.addEventListener("mousemove", (e) => mousedown && scrub(e)) progress.addEventListener("mousedown", () => (mousedown = true)) progress.addEventListener("mouseup", () => (mousedown = false))
o scrub()
A função requer um argumento de evento que ouvimos. Em particular, o offsetX
A propriedade nos permite identificar onde um usuário clicou e fazer cálculos relativos às propriedades do audioElement.
Por fim, podemos ouvir na própria barra de progresso um conjunto de eventos como clique, mousemove, mousedowne mouseup para ajustar o elemento de áudio currentTime
propriedade.
4. Juntando tudo
O código JavaScript final está abaixo. Uma coisa a observar é o carregamento da primeira página; eu chamo o setTimes()
funcionar mais uma vez para que possamos exibir em tempo real corretamente antes que o usuário comece a manipular o reprodutor de áudio.
// load sound via
Conclusão
Aí está! Com um pouco de JavaScript e graxa de cotovelo, você pode criar seu próprio reprodutor de música de marca.
A partir daqui, você pode experimentar adicionar mais controles, como pular botões ou botões panorâmicos. Eu também verificaria a interface AudioTracklist, que permite criar listas de reprodução e estender o design conforme necessário.