react18.x+播放文本内容

需要调接口将文字传递给后端将文字转换成音频文件,然后播放,同时每次播放不同文本时,当前播放的文本需要暂停,切换到播放新点击的文本

可以设置缓存播放过的音频,也可以不设置缓存:

设置缓存的代码如下:

javascript 复制代码
import React, { useState, useCallback, useRef } from "react";
import { Button, Tooltip } from "antd";
import { SoundOutlined } from "@ant-design/icons";
import { getMp3AudioByText } from "./api/audio";

const Home = () => {
  const [texts, setTexts] = useState([
    { id: 1, text: "useEffect:允许你将组件与外部系统同步" },
    { id: 2, text: "useCallback:是一个允许在多次渲染中缓存函数的React Hook" },
    { id: 3, text: "useRef:能帮助引用一个不需要渲染的值" },
    { id: 4, text: "useState:向组件添加一个状态变量" },
    { id: 5, text: "useMemo:在每次重新渲染的时候能够缓存计算的结果" },
    { id: 6, text: "useId:是一个可以生成传递给无障碍属性的唯一 ID" },
  ]);

  const [currentAudio, setCurrentAudio] = useState<HTMLAudioElement | null>(
    null
  );
  const audioCache = useRef<{ [key: string]: string }>({});
  const cacheOrder = useRef<string[]>([]);
  const MAX_CACHE_SIZE = 5;

  const playMp3Audio = useCallback(
    async (content: string) => {
      try {
        if (currentAudio) {
          currentAudio.pause(); // 如果当前有正在播放的音频,暂停音频
          currentAudio.currentTime = 0; // 重置音频的当前播放时间
          setCurrentAudio(null); // 清除当前音频元素的状态
        }

        if (audioCache.current[content]) {
          // 如果缓存中有对应的音频URL,直接播放
          const audio = new Audio(audioCache.current[content]);
          audio.play().catch((playError) => {
            console.error("无法播放音频", playError);
            return;
          });

          setCurrentAudio(audio); // 更新当前音频元素状态
          audio.addEventListener("ended", () => setCurrentAudio(null));
        } else {
          // 否则发送请求获取音频
          const response: any = await getMp3AudioByText({ text: content });
          const blob = new Blob([response], { type: "audio/mp3" });
          const url = URL.createObjectURL(blob);

          // 将音频URL存入缓存
          if (cacheOrder.current.length >= MAX_CACHE_SIZE) {
            const oldestKey = cacheOrder.current.shift()!;
            URL.revokeObjectURL(audioCache.current[oldestKey]);
            delete audioCache.current[oldestKey];
          }

          audioCache.current[content] = url;
          cacheOrder.current.push(content);

          const audio = new Audio(url);
          audio.play().catch((playError) => {
            console.error("无法播放音频", playError);
            return;
          });

          setCurrentAudio(audio); // 更新当前音频元素状态
          audio.addEventListener("ended", () => setCurrentAudio(null));
        }
      } catch (error) {
        console.error(error);
      }
    },
    [currentAudio]
  );

  return (
    <div>
      {texts.map((item) => (
        <div key={item.id}>
          {item.text}
          <Tooltip title="播放文本" color="pink">
            <Button
              shape="round"
              size="small"
              icon={<SoundOutlined style={{ fontSize: "14px" }} />}
              onClick={() => playMp3Audio(item.text)}
            />
          </Tooltip>
        </div>
      ))}
    </div>
  );
};

export default Home;

不缓存,每次点击都发送请求

javascript 复制代码
import React, { useState, useCallback } from "react";
import classNames from "classnames";
import { Button, Tooltip } from "antd";
import { SoundOutlined } from "@ant-design/icons";
import { getMp3AudioByText } from "./api/audio";

const Home = () => {
  const [texts, setTexts] = useState([
    { id: 1, text: "useEffect:允许你将组件与外部系统同步" },
    { id: 2, text: "useCallback:是一个允许在多次渲染中缓存函数的React Hook" },
    { id: 3, text: "useRef:能帮助引用一个不需要渲染的值" },
    { id: 4, text: "useState:向组件添加一个状态变量" },
    { id: 5, text: "useMemo:在每次重新渲染的时候能够缓存计算的结果" },
    { id: 6, text: "useId:是一个可以生成传递给无障碍属性的唯一 ID" },
  ]);

  const [currentAudio, setCurrentAudio] = useState<HTMLAudioElement | null>(
    null
  );

  const playMp3Audio = useCallback(
    async (content: string) => {
      try {
        if (currentAudio) {
          currentAudio.pause();// 如果当前有正在播放的音频,暂停音频
          currentAudio.currentTime = 0;// 重置音频的当前播放时间
          setCurrentAudio(null);// 清除当前音频元素的状态
        }

        const response: any = await getMp3AudioByText({ text: content });
        // 将返回的数据转化为Blob
        const blob = new Blob([response], { type: "audio/mp3" });
        const url = URL.createObjectURL(blob);
        
        // 创建一个新的audio元素来播放mp3文件
        const audio = new Audio(url);
        audio.play().catch((playError) => {
          console.error("无法播放音频", playError);
          return;
        });

        setCurrentAudio(audio); // 更新当前音频元素状态
        // 添加'ended'事件监听器,当音频播放结束时设置currentAudio为null
        audio.addEventListener("ended", () => setCurrentAudio(null));
        
      } catch (error) {
        console.error(error);
      }
    },
    [currentAudio]
  );

  return (
    <div>
      {texts.map((item, index) => (
        <div key={index}>
          {item.text}
          <Tooltip title="播放文本" color="pink">
            <Button
              shape="round"
              size="small"
              icon={<SoundOutlined style={{ fontSize: "14px" }} />}
              onClick={() => playMp3Audio(item.text)}
            />
          </Tooltip>
        </div>
      ))}
    </div>
  );
};

export default Home;
相关推荐
lly2024064 分钟前
Kotlin 类和对象
开发语言
是苏浙9 分钟前
零基础入门C语言之C语言内存函数
c语言·开发语言
zhmhbest10 分钟前
Qt 全球峰会 2025:中国站速递 —— 技术中立,拥抱更大生态
开发语言·qt·系统架构
程序员大雄学编程10 分钟前
用Python来学微积分30-微分方程初步
开发语言·python·线性代数·数学·微积分
关于不上作者榜就原神启动那件事15 分钟前
模拟算法乒乓球
开发语言·c++·算法
88号技师43 分钟前
2025年7月一区SCI优化算法-Logistic-Gauss Circle optimizer-附Matlab免费代码
开发语言·算法·数学建模·matlab·优化算法
uuai1 小时前
echarts不同版本显示不一致问题
前端·javascript·echarts
自然 醒1 小时前
企业微信自建应用开发详细教程,如何获取授权链接?如何使用js-sdk?
javascript·vue.js·企业微信
再睡一夏就好1 小时前
【C++闯关笔记】unordered_map与unordered_set的底层:哈希表(哈希桶)
开发语言·c++·笔记·学习·哈希算法·散列表
potato_15541 小时前
现代C++核心特性——内存篇
开发语言·c++·学习