当前位置: 首页 > news >正文

react18.x+播放文本内容

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

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

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"><Buttonshape="round"size="small"icon={<SoundOutlined style={{ fontSize: "14px" }} />}onClick={() => playMp3Audio(item.text)}/></Tooltip></div>))}</div>);
};export default Home;

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

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 });// 将返回的数据转化为Blobconst 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为nullaudio.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"><Buttonshape="round"size="small"icon={<SoundOutlined style={{ fontSize: "14px" }} />}onClick={() => playMp3Audio(item.text)}/></Tooltip></div>))}</div>);
};export default Home;

相关文章:

  • Appium adb 获取appActivity
  • Laravel swagger接口文档生成和管理
  • 数据结构与算法—空间复杂度详解与示例(C#,C++)
  • 【力扣 - 每日一题】3115. 质数的最大距离(一次遍历、头尾遍历、空间换时间、埃式筛、欧拉筛、打表)Golang实现
  • Halcon机器视觉定位--模板匹配
  • Android启动时间分析
  • 7.2总结
  • 计算机相关术语科普之什么叫网关(Gateway)
  • llama3模型部署时遇到的问题及解决方案
  • 【ONLYOFFICE】| 桌面编辑器从0-1使用初体验
  • mysql创建表的规范
  • 鸿蒙开发设备管理:【@ohos.multimodalInput.touchEvent (触摸输入事件)】
  • XPath 语法笔记
  • DP:子序列问题
  • elasticsearch导出和导入数据
  • 深入了解以太坊
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • overflow: hidden IE7无效
  • spring + angular 实现导出excel
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 译自由幺半群
  • No resource identifier found for attribute,RxJava之zip操作符
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​520就是要宠粉,你的心头书我买单
  • ​queue --- 一个同步的队列类​
  • #{}和${}的区别?
  • #HarmonyOS:Web组件的使用
  • #NOIP 2014# day.1 T2 联合权值
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • $nextTick的使用场景介绍
  • (12)Hive调优——count distinct去重优化
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (五)Python 垃圾回收机制
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (一)UDP基本编程步骤
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • ****Linux下Mysql的安装和配置
  • ../depcomp: line 571: exec: g++: not found
  • .NET 5种线程安全集合
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .net 发送邮件
  • .net2005怎么读string形的xml,不是xml文件。
  • /etc/skel 目录作用
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [Asp.net MVC]Asp.net MVC5系列——Razor语法
  • [BZOJ 3282] Tree 【LCT】