需要调接口将文字传递给后端将文字转换成音频文件,然后播放,同时每次播放不同文本时,当前播放的文本需要暂停,切换到播放新点击的文本
可以设置缓存播放过的音频,也可以不设置缓存:
设置缓存的代码如下:
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;