我开始学习react.js已经有一段时间了,但现在我在播放和暂停子组件LessonCard.jsx的音频时遇到问题。当我单击 LessonCard.jsx 中的播放按钮时,它正在播放音频,这是另一个组件 AudioPlayer.jsx 但问题是,当我暂停 LessonCard.jsx 中的音频时,按钮的图标会发生变化,但音频是没有暂停。
Home.jsx
import React, { useState, useEffect } from "react";
import sanityClient from "../client";
import CategoryCard from "./CategoryCard";
import LessonCard from "./LessonCard";
import AudioPlayer from "./AudioPlayer";
const Home = () => {
const [lessons, setLessons] = useState(null);
const [loading, setLoading] = useState(true);
const [audioUri, setAudioUri] = useState(null);
const [isAudioPlaying, setIsAudioPlaying] = useState(false);
const handleCardClick = (audioUri) => {
setAudioUri(audioUri);
setIsAudioPlaying((prevIsAudioPlaying) => !prevIsAudioPlaying);
};
// const query = '*[_type == "lessons"]';
useEffect(() => {
const fetchData = async () => {
try {
const result = await sanityClient.fetch(`*[_type == 'lessons']{
_id,
lessonTitle,
category,
uploadDate,
body,
'audio': audio.asset->url
}`);
setLessons(result);
setLoading(false);
// console.log(result);
} catch (error) {
console.error("Error fetching data from Sanity:", error);
setLoading(false);
}
};
fetchData();
}, []);
return (
<main className="container 2xl:max-w-[1280px] mx-auto min-h-[100vh] px-4 py-16">
<div>
<h2 className="mt-[2rem] text-3xl ff-bold font-semibold text-[color:var(--deep-green)]">
Categories
</h2>
<CategoryCard />
<h2 className="mt-[3rem] text-3xl ff-bold font-semibold text-[color:var(--deep-green)]">
All available lessons
</h2>
<div
className={`min-h-[50vh] ${
loading ? "flex items-center justify-center" : ""
}`}
>
{loading ? (
<div className="text-center text-xl">Loading...</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5 sm:gap-3 mt-6">
{lessons?.map((lesson, idx) => {
const { lessonTitle, category, uploadDate, audio } = lesson;
return (
<LessonCard
key={idx}
lessonTitle={lessonTitle}
category={category}
publishDate={uploadDate}
audioUri={audio}
// isAudioPlaying={isAudioPlaying}
isAudioPlaying={audioUri === lesson.audio && isAudioPlaying}
setIsAudioPlaying={setIsAudioPlaying}
setAudioUri={setAudioUri}
/>
);
})}
</div>
)}
</div>
</div>
<AudioPlayer
audioUri={audioUri}
isAudioPlaying={isAudioPlaying}
setIsAudioPlaying={setIsAudioPlaying}
/>
</main>
);
};
export default Home;
LessonCard.jsx
import React, { useRef } from "react";
const LessonCard = ({
lessonTitle,
category,
publishDate,
audioUri,
isAudioPlaying,
setIsAudioPlaying,
setAudioUri,
}) => {
const lessonCardRef = useRef(null);
const handleCardPlay = () => {
setAudioUri(audioUri);
setIsAudioPlaying((prevIsAudioPlaying) => !prevIsAudioPlaying);
};
return (
<div
ref={lessonCardRef}
onClick={handleCardPlay}
className="lesson-card w-full bg-white border border-slate-200 hover:border-[color:var(--deep-green)] duration-150 h-[70px] px-2 rounded-[7px] cursor-pointer group flex justify-between active:border-[color:var(--deep-green)]"
>
<div className="w-full h-full flex items-center">
<div className="h-full flex items-center justify-center">
<button className="[color:var(--deep-green)] bg-slate-100 w-[40px] h-[40px] rounded-full group-hover:bg-slate-500 group-hover:text-white duration-150 flex items-center justify-center font-semibold text-lg mr-3">
<i className={isAudioPlaying ? "fa fa-pause" : "fa fa-play"}></i>
</button>
</div>
<div className="flex-1">
<p className="text-lg truncate text-ellipsis line-clamp-1 break-words whitespace-normal">
{lessonTitle}
</p>
<div className="flex items-center justify-between">
<p className="text-sm capitalize text-[color:rgba(0,0,0,0.7)]">
{category}
</p>
<p className="[font-size:0.75rem] text-[color:rgba(0,0,0,0.7)]">
{publishDate}
</p>
</div>
</div>
<div className="hidden w-[40px] h-[40px] rounded-full bg-slate-200 items-center justify-center">
<button>
<i className="fa fa-download"></i>
</button>
</div>
</div>
</div>
);
};
export default LessonCard;
音频播放器.jsx
import React, { useEffect, useRef, useState } from "react";
import WaveSurfer from "wavesurfer.js";
const AudioPlayer = ({ audioUri, isAudioPlaying, setIsAudioPlaying }) => {
const playerRef = useRef(null);
// const [isPlaying, setIsPlaying] = useState(false);
const wavesurferRef = useRef(null);
const handlePlay = () => {
if (wavesurferRef.current) {
if (isAudioPlaying) {
wavesurferRef.current.pause();
} else {
wavesurferRef.current.play();
}
setIsAudioPlaying(!isAudioPlaying);
}
};
const downloadAudio = () => {
const link = document.createElement("a");
link.href = audioUri;
link.download = "your-audio.mp3";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
setTimeout(() => {
link.remove();
}, 50);
};
useEffect(() => {
wavesurferRef.current = WaveSurfer.create({
container: playerRef.current,
waveColor: "#BFCEBF",
progressColor: "#1e8a69",
cursorColor: "transparent",
barWidth: 3,
barHeight: 2,
barGap: 2,
barRadius: 5,
height: 60,
normalize: true,
responsive: true,
dragToSeek: true,
autoScroll: true,
});
// Load the audio file when the URI changes
if (wavesurferRef.current) {
if (audioUri) {
wavesurferRef.current.load(audioUri);
wavesurferRef.current.on("ready", () => {
if (isAudioPlaying) {
wavesurferRef.current.play();
} else {
wavesurferRef.current.pause();
}
});
}
}
return () => {
wavesurferRef.current.destroy();
};
}, [audioUri]);
return (
<div className="container mx-auto 2xl:max-w-[1280px]">
<div
className={`${
audioUri
? "fixed bottom-0 left-0 z-20 bg-slate-100 w-full px-4 py-2 flex items-center justify-center translate-y-[0%] [transition:300ms]"
: "translate-y-[100%]"
}`}
>
<div className="max-w-[37rem] mx-auto w-full flex items-center">
<div
onClick={handlePlay}
className={`${
audioUri ? "flex items-center justify-center mr-4" : "hidden"
}`}
>
<button className="w-[35px] h-[35px] sm:w-[40px] sm:h-[40px] rounded-full bg-[var(--deep-green)]">
<i
className={`fa ${
isAudioPlaying ? "fa-pause" : "fa-play"
} text-white duration-150`}
></i>
</button>
</div>
<div ref={playerRef} className="player w-full z-40 gap-2 sm:gap-4">
<div
onClick={downloadAudio}
className={`${
audioUri ? "flex items-center justify-center" : "hidden"
}`}
>
<button className="w-[35px] h-[35px] sm:w-[40px] sm:h-[40px] rounded-full bg-slate-200 hover:bg-[var(--deep-green)] group duration-150">
<i className="fa fa-download text-[var(--deep-green)] group-hover:text-white duration-150"></i>
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default AudioPlayer;
我尝试播放 LessonCard.jsx 组件中的音频,但它不起作用。
在您的
AudioPlayer
组件中,每当 isAudioPlaying
状态在组件外部发生更改时(即当用户按下课程卡时),就没有暂停/播放 wavesurfer
的指令。您可以在 useEffect
组件中添加以下 AudioPlayer
钩子:
useEffect(() => {
if (isAudioPlaying) {
wavesurferRef.current?.play();
} else {
wavesurferRef.current?.pause();
}
}, [isAudioPlaying]);
这意味着每当状态
isAudioPlaying
更新时,wavesurfer
就会相应地播放或暂停。此外,您可以简化您的 handlePlay
函数:
const handlePlay = () => {
setIsAudioPlaying(isAudioPlaying => !isAudioPlaying);
};