Перейти к содержимому

Аудио плеер

Иконки
yarn add react-icons

Стили

./styles/AudioPlayer.module.css
.audioPlayer {
--primary: #f40082;
--secondary: #ffd200;
align-items: center;
display: flex;
width: 700px;
}
.forwardBackward {
background: none;
border: none;
display: flex;
align-items: center;
font-family: monospace;
font-size: 16px;
cursor: pointer;
}
.forwardBackward:hover {
color: var(--primary);
}
.playPause {
background: var(--primary);
border: none;
border-radius: 50%;
width: 75px;
height: 75px;
font-size: 32px;
color: var(--secondary);
display: flex;
justify-content: center;
align-items:center;
}
.play {
position: relative;
left: 5px;
}
.currentTime,
.duration {
font-family: monospace;
font-size: 16px;
}
.currentTime {
margin-left: 25px;
}
.progressBar {
--bar-bg: #ffe3d4;
--seek-before-width: 0;
--seek-before-color: #ffc2a1;
--knobby: #3452a5;
--selectedKnobby: #26c9c3;
appearance: none;
background: var(--bar-bg);;
border-radius: 10px;
position: relative;
width: 100%;
height: 11px;
outline: none;
}
/* progress bar - safari */
.progressBar::-webkit-slider-runnable-track {
background: var(--bar-bg);;
border-radius: 10px;
position: relative;
width: 100%;
height: 11px;
outline: none;
}
/* progress bar - firefox */
.progressBar::-moz-range-track {
background: var(--bar-bg);;
border-radius: 10px;
position: relative;
width: 100%;
height: 11px;
outline: none;
}
.progressBar::-moz-focus-outer {
border: 0;
}
/* progress bar - chrome and safari */
.progressBar::before {
content: '';
height: 11px;
width: var(--seek-before-width);
background-color: var(--seek-before-color);
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
position: absolute;
top: 0;
left: 0;
z-index: 2;
cursor: pointer;
}
/* progress bar - firefox */
.progressBar::-moz-range-progress {
background-color: var(--seek-before-color);
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
height: 11px;
}
/* knobby - chrome and safari */
.progressBar::-webkit-slider-thumb {
-webkit-appearance: none;
height: 15px;
width: 15px;
border-radius: 50%;
border: none;
background-color: var(--knobby);
cursor: pointer;
position: relative;
margin: -2px 0 0 0;
z-index: 3;
box-sizing: border-box;
}
/* knobby while dragging - chrome and safari */
.progressBar:active::-webkit-slider-thumb {
transform: scale(1.2);
background: var(--selectedKnobby);
}
/* knobby - firefox */
.progressBar::-moz-range-thumb {
height: 15px;
width: 15px;
border-radius: 50%;
border: transparent;
background-color: var(--knobby);
cursor: pointer;
position: relative;
z-index: 3;
box-sizing: border-box;
}
/* knobby while dragging - firefox */
.progressBar:active::-moz-range-thumb {
transform: scale(1.2);
background: var(--selectedKnobby);
}

Компонент

./components/AudioPlayer.jsx
'use client'
import React, { useState, useRef, useEffect } from 'react'
import styles from "../../styles/AudioPlayer.module.css"; // Укажите путь к файлу
import { BsArrowLeftShort } from "react-icons/bs"
import { BsArrowRightShort } from "react-icons/bs"
import { FaPlay } from "react-icons/fa"
import { FaPause } from "react-icons/fa"
const AudioPlayer = () => {
// state
const [isPlaying, setIsPlaying] = useState(false);
const [duration, setDuration] = useState(0);
const [currentTime, setCurrentTime] = useState(0);
// references
const audioPlayer = useRef(); // reference our audio component
const progressBar = useRef(); // reference our progress bar
const animationRef = useRef(); // reference the animation
useEffect(() => {
const seconds = Math.floor(audioPlayer.current.duration);
setDuration(seconds);
progressBar.current.max = seconds;
}, [audioPlayer?.current?.loadedmetadata, audioPlayer?.current?.readyState]);
const calculateTime = (secs) => {
const minutes = Math.floor(secs / 60);
const returnedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
const seconds = Math.floor(secs % 60);
const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
return `${returnedMinutes}:${returnedSeconds}`;
}
const togglePlayPause = () => {
const prevValue = isPlaying;
setIsPlaying(!prevValue);
if (!prevValue) {
audioPlayer.current.play();
animationRef.current = requestAnimationFrame(whilePlaying)
} else {
audioPlayer.current.pause();
cancelAnimationFrame(animationRef.current);
}
}
const whilePlaying = () => {
progressBar.current.value = audioPlayer.current.currentTime;
changePlayerCurrentTime();
animationRef.current = requestAnimationFrame(whilePlaying);
}
const changeRange = () => {
audioPlayer.current.currentTime = progressBar.current.value;
changePlayerCurrentTime();
}
const changePlayerCurrentTime = () => {
progressBar.current.style.setProperty('--seek-before-width', `${progressBar.current.value / duration * 100}%`)
setCurrentTime(progressBar.current.value);
}
const backThirty = () => {
progressBar.current.value = Number(progressBar.current.value - 30);
changeRange();
}
const forwardThirty = () => {
progressBar.current.value = Number(progressBar.current.value + 30);
changeRange();
}
return (
<div className={styles.audioPlayer}>
<audio ref={audioPlayer} src="https://listen.myrh.ru/id075696" preload="metadata"></audio>
<button className={styles.forwardBackward} onClick={backThirty} title="Back"><BsArrowLeftShort /> 30</button>
<button onClick={togglePlayPause} className={styles.playPause} title="Play/Pause">
{isPlaying ? <FaPause /> : <FaPlay className={styles.play} />}
</button>
<button className={styles.forwardBackward} onClick={forwardThirty} title="Next">30 <BsArrowRightShort /></button>
{/* current time */}
<div className={styles.currentTime}>{calculateTime(currentTime)}</div>
{/* progress bar */}
<div>
<input type="range" className={styles.progressBar} defaultValue="0" ref={progressBar} onChange={changeRange} />
</div>
{/* duration */}
<div className={styles.duration}>{(duration && !isNaN(duration)) && calculateTime(duration)}</div>
</div>
)
}
export { AudioPlayer }

Плеер

./app/page.tsx
import { AudioPlayer } from "../components/AudioPlayer" // Укажите путь к файлу
export default function Page() {
return (
<div>
<AudioPlayer />
</div>
)
}