You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React子组件LessonCard控制AudioPlayer播放暂停失效问题

问题原因分析
  • AudioPlayer未同步播放状态:仅在audioUri变化时初始化播放器,后续isAudioPlaying状态变更无法触发WaveSurfer实例的播放/暂停操作。
  • LessonCard点击逻辑冗余:每次点击都强制设置audioUri,即使是同一音频也会触发AudioPlayer重新加载,导致暂停操作被覆盖。
  • 状态双向绑定缺失:WaveSurfer自身的播放状态未与React的isAudioPlaying同步,仅初始化时处理一次,后续状态变更脱节。
修复方案

1. 给AudioPlayer添加状态监听,同步控制播放器

修改AudioPlayer.jsx,新增监听isAudioPlaying的useEffect,同时绑定WaveSurfer的播放/暂停事件同步React状态:

import React, { useEffect, useRef } from "react";
import WaveSurfer from "wavesurfer.js";

const AudioPlayer = ({ audioUri, isAudioPlaying, setIsAudioPlaying }) => {
  const playerRef = useRef(null);
  const wavesurferRef = useRef(null);

  const handlePlay = () => {
    if (wavesurferRef.current) {
      wavesurferRef.current.togglePlay(); // 直接调用WaveSurfer的切换方法
    }
  };

  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,
    });

    // 绑定WaveSurfer事件,同步到React状态
    wavesurferRef.current.on("play", () => setIsAudioPlaying(true));
    wavesurferRef.current.on("pause", () => setIsAudioPlaying(false));

    if (audioUri) {
      wavesurferRef.current.load(audioUri);
      wavesurferRef.current.on("ready", () => {
        isAudioPlaying ? wavesurferRef.current.play() : wavesurferRef.current.pause();
      });
    }

    return () => wavesurferRef.current.destroy();
  }, [audioUri]);

  // 新增:监听React状态变化,同步控制播放器
  useEffect(() => {
    if (wavesurferRef.current) {
      isAudioPlaying ? wavesurferRef.current.play() : wavesurferRef.current.pause();
    }
  }, [isAudioPlaying]);

  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;

2. 修改LessonCard点击逻辑,避免重复加载音频

首先在Home.jsx中给LessonCard传递当前激活的音频地址:

<LessonCard
  key={idx}
  lessonTitle={lessonTitle}
  category={category}
  publishDate={uploadDate}
  audioUri={audio}
  currentActiveAudio={audioUri} // 新增:传递当前播放的音频地址
  isAudioPlaying={audioUri === lesson.audio && isAudioPlaying}
  setIsAudioPlaying={setIsAudioPlaying}
  setAudioUri={setAudioUri}
/>

然后修改LessonCard.jsx的点击逻辑,仅在切换音频时设置audioUri:

import React, { useRef } from "react";

const LessonCard = ({
  lessonTitle,
  category,
  publishDate,
  audioUri,
  currentActiveAudio,
  isAudioPlaying,
  setIsAudioPlaying,
  setAudioUri,
}) => {
  const lessonCardRef = useRef(null);

  const handleCardPlay = () => {
    if (currentActiveAudio !== audioUri) {
      // 切换到新音频,直接播放
      setAudioUri(audioUri);
      setIsAudioPlaying(true);
    } else {
      // 同一音频,仅切换播放状态
      setIsAudioPlaying((prev) => !prev);
    }
  };

  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;
修复效果验证
  • 点击未播放的卡片:音频加载并自动播放,按钮图标切换为暂停。
  • 点击正在播放的卡片:音频暂停,按钮图标切换为播放。
  • 点击其他卡片:当前音频暂停,新音频加载并播放。
  • 点击底部播放器的控制按钮:卡片图标与播放状态同步变化。

内容的提问来源于stack exchange,提问作者shahid khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:14:58