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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/37535.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

骁龙相机拍照流程分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 1.deliverInputEvent 拍照点击事件处理 2.submitRequestList Camera 提交拍照请求 3.createCaptureRequest 拍照请求帧数 骁龙相机通过binder 数据传输…

idea 内存参数修改不生效问题解决 VM参数设置不生效解决

很多人配置idea 内存参数&#xff0c;怎么配置都不生效&#xff0c;主要原因是配置文件用的不是你修改的那个。 系统环境变量中的这个才是你真正要修改的配置文件。 找到并修改后保存&#xff0c;重启idea就可生效

C++ | Leetcode C++题解之第208题实现Trie(前缀树)

题目&#xff1a; 题解&#xff1a; class Trie { private:vector<Trie*> children;bool isEnd;Trie* searchPrefix(string prefix) {Trie* node this;for (char ch : prefix) {ch - a;if (node->children[ch] nullptr) {return nullptr;}node node->children[…

人工与智能系统之间的交互方式

人工与智能系统之间的交互方式 #mermaid-svg-xSsFZWak2bsyV0un {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xSsFZWak2bsyV0un .error-icon{fill:#552222;}#mermaid-svg-xSsFZWak2bsyV0un .error-text{fill:#5522…

分词算法在自然语言处理中的基本原理与应用场景

分词算法在自然语言处理中的基本原理与应用场景 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 分词是自然语言处理&#xff08;NLP&#xff09;中的重要基础…

python脚本 限制 外部访问 linux服务器端口

注意&#xff1a;该脚本会清空linux防火墙的filter表的规则和用户自定义链路 脚本的效果是将端口限制为仅服务器内部访问&#xff0c;提高服务的安全性&#xff0c;稳定性 可以提供ip地址白名单 具体脚本&#xff1a; #!/usr/bin/python3 import argparse, subprocess, sys,…

13_网络安全

目录 网络安全协议 网络安全协议 PGP协议 网络安全技术 防火墙技术 入侵检测系统 入侵防御系统 杀毒软件 蜜罐系统 计算机病毒与木马 网络安全协议 网络安全协议 物理层主要使用物理手段隔离、屏蔽物理设备等&#xff0c;其他层都是靠协议来保证传输的安全&#xff…

美国服务器租用详细介绍与租用流程

在数字化时代&#xff0c;服务器租用已成为许多企业和个人拓展业务、存储数据的重要选择。美国作为全球科技发展的前沿阵地&#xff0c;其服务器租用服务也备受瞩目。下面&#xff0c;我们将详细介绍美国服务器租用的相关知识及租用流程。 一、美国服务器租用简介 美国服务器租…

中英双语介绍美国的州:新泽西州(New Jersey)

中文版 新泽西州&#xff08;New Jersey&#xff09;位于美国东北部&#xff0c;是美国面积较小但人口密度较高的州之一。新泽西州因其便利的地理位置、发达的经济和丰富的历史文化而闻名。以下是对新泽西州各方面的详细介绍&#xff1a; 人口 截至2020年&#xff0c;美国人…

引领汽车软件开发走向ASPICE认证之路

亚远景科技与ASPICE认证的关系可以从以下几个方面来阐述&#xff1a; (要明确的是&#xff1a;在ASPICE行业中专业来说&#xff0c;ASPICE项目是没有认证&#xff0c;而只有评估。不过&#xff0c;为了方便沟通&#xff0c;人们常将这一评估过程称为认证。&#xff09; 行业专…

tomcat定时重启

Tomcat定时重启&#xff08;linux&#xff09; 1. 编写脚本 在tomcat的bin目录下&#xff0c;使用vim restart.sh&#xff0c;编写restart.sh脚本&#xff0c;插入一下内容&#xff0c;最后并保存&#xff01; #!/bin/bash# 初始化全局环境变量 . /etc/profilecd /usr/loca…

探索数据结构:队列的的实现与应用

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;渐入佳境之数据结构与算法 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 一、队列的概念 队列是一个线性的数据结构&#…

windows环境下创建python虚拟环境

windows环境下创建python虚拟环境 使用virtualenv库创建虚拟环境&#xff0c;可使不同的项目处于不同的环境中 安装方法&#xff1a; pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple pip install virtualenvwrapper-win -i https://pypi.tuna.tsinghua…

Spring Cloud Alibaba之负载均衡组件Ribbon

一、什么是负载均衡&#xff1f; &#xff08;1&#xff09;概念&#xff1a; 在基于微服务架构开发的系统里&#xff0c;为了能够提升系统应对高并发的能力&#xff0c;开发人员通常会把具有相同业务功能的模块同时部署到多台的服务器中&#xff0c;并把访问业务功能的请求均…

谈谈WebComponents | 前端开发

一、 源起 让我们以一个例子开始。 假设我们要做一个环形进度条&#xff0c;它可以&#xff1a; 1、根据进度数值的不同&#xff0c;计算出百分比&#xff0c;以渲染对应的角度值。 2、根据设置的进度不同&#xff0c;我们用不同的颜色加以区分。 3、在环的中间我们以动画递增的…

小程序、APP对接广告联盟进行广告变现有什么区别?

小程序VS APP对接广告联盟有什么区别&#xff1f; 开发完成的小程序对接广告联盟广告变现&#xff0c;开发完成的APP对接广告联盟有什么区别&#xff1f; 首先小程序对接广告联盟&#xff0c;无论是微信小程序还是抖音小程序都只支持对接单一的广告联盟接入。抖音小程序只支持…

【监控】监控平台部署 Prometheus+Grafana

在 macOS 上部署 Grafana 和 Prometheus 来监控 Java 服务是一个非常实用的操作。以下是详细的步骤&#xff0c;包括如何安装和配置 Prometheus、Grafana 以及在 Java 服务中集成 Prometheus 的客户端库来收集指标数据。 1. 安装 Prometheus 1.1 使用 Homebrew 安装 Promethe…

简单分享项目内如何快速自动生成自己的库和更新 requirements.txt

当开发Python项目时&#xff0c;requirements.txt文件被用来清单所有所需的Python包及其版本。这个文件对于在不同环境中安装和管理项目依赖特别方便&#xff0c;无论是在生产环境、开发环境或者CI/CD流程中。 要自动创建和更新requirements.txt文件&#xff0c;有几种常见的方…

深入剖析 @Autowired 和 @Resource 在 Spring 中的区别

在 Spring 框架中&#xff0c;Autowired 和 Resource 是两个常用的注解&#xff0c;用于实现依赖注入。尽管它们都能达到将依赖对象注入到目标 bean 的目的&#xff0c;但在细节上存在一些显著的差异。本文将深入探讨这两个注解的区别&#xff0c;并结合 Spring 源码进行分析&a…

vision mamba

Mamba 成功的关键在于采用了 Selective Scan Space State Sequential Model&#xff08;S6 模型&#xff09;。是用于解决自然语言处理&#xff08;NLP&#xff09;任务。与 transformer中注意力机制不同&#xff0c;Mamba的S6 将 1D 向量中的每个元素&#xff08;例如文本序列…