React JS中如何裁剪音频末尾几秒及实现音频无停顿循环?
React音频功能实现方案
无停顿音频循环播放实现
原生<audio>标签的loop属性播放结束后会重新触发资源加载、解码逻辑,必然产生停顿间隙,可通过以下两种方案解决:
- 最优方案:Web Audio API实现
Web Audio API直接操作音频二进制缓冲区,天生支持无间隙循环,React中实现示例:
import { useRef, useEffect, useState } from 'react'; const AudioLoopPlayer = () => { const audioContextRef = useRef(null); const sourceRef = useRef(null); const [isPlaying, setIsPlaying] = useState(false); const initAndPlay = async () => { // 浏览器限制AudioContext必须在用户交互后初始化 if (!audioContextRef.current) { audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)(); } // 加载并解码音频 const res = await fetch('/你的音频地址.mp3'); const arrayBuffer = await res.arrayBuffer(); const audioBuffer = await audioContextRef.current.decodeAudioData(arrayBuffer); // 创建播放节点 sourceRef.current = audioContextRef.current.createBufferSource(); sourceRef.current.buffer = audioBuffer; sourceRef.current.loop = true; // 开启循环无间隙 sourceRef.current.connect(audioContextRef.current.destination); sourceRef.current.start(0); setIsPlaying(true); }; return <button onClick={initAndPlay}>{isPlaying ? '播放中' : '点击播放'}</button>; };
- 轻量替代方案:双音频实例轮播
如果不想引入Web Audio的复杂逻辑,可以预加载两个相同的音频实例,当前实例播放到结束前100ms时触发另一个实例播放,交替实现接近无间隙的循环效果。
音频末尾裁剪实现方案
播放端裁剪(无需修改源文件)
原生HTML标签没有直接裁剪属性,可通过事件监听控制播放范围,适合仅需要播放时裁剪、不需要修改源文件的场景:
import { useRef } from 'react'; const CutAudioPlayer = ({ cutSeconds = 3 }) => { // 默认裁剪末尾3秒 const audioRef = useRef(null); const endTimeRef = useRef(0); const handleLoadedMetadata = () => { // 计算实际播放结束时间:总时长减去要裁剪的秒数 endTimeRef.current = audioRef.current.duration - cutSeconds; }; const handleTimeUpdate = () => { if (audioRef.current.currentTime >= endTimeRef.current) { audioRef.current.pause(); // 如果是循环播放可以在这里直接把currentTime设为0再play // audioRef.current.currentTime = 0; // audioRef.current.play(); } }; return ( <audio ref={audioRef} src="/你的音频地址.mp3" controls onLoadedMetadata={handleLoadedMetadata} onTimeUpdate={handleTimeUpdate} /> ); };
源文件裁剪(React集成FFmpeg方案)
如果需要直接裁剪生成新的音频文件,可以使用WASM版本的FFmpeg @ffmpeg/ffmpeg 纯前端实现,无需后端服务:
- 先安装依赖:
npm install @ffmpeg/ffmpeg @ffmpeg/core - React组件实现示例:
import { useState } from 'react'; import { FFmpeg } from '@ffmpeg/ffmpeg'; import { fetchFile } from '@ffmpeg/util'; const AudioCutter = () => { const [processedAudioUrl, setProcessedAudioUrl] = useState(''); const ffmpeg = new FFmpeg(); const cutAudio = async (file, cutSeconds = 3) => { // 加载FFmpeg核心 await ffmpeg.load(); // 写入源文件到FFmpeg虚拟文件系统 ffmpeg.writeFile('input.mp3', await fetchFile(file)); // 获取音频总时长计算裁剪后时长,可用audio元数据方法自行实现getAudioDuration const duration = await getAudioDuration(file); const targetDuration = duration - cutSeconds; // 执行裁剪命令 await ffmpeg.exec(['-i', 'input.mp3', '-t', targetDuration.toString(), '-c:a', 'copy', 'output.mp3']); // 读取处理后的文件 const data = await ffmpeg.readFile('output.mp3'); // 生成可播放的blob地址 const url = URL.createObjectURL(new Blob([data], { type: 'audio/mpeg' })); setProcessedAudioUrl(url); }; return ( <div> <input type="file" accept="audio/*" onChange={(e) => cutAudio(e.target.files[0])} /> {processedAudioUrl && <audio src={processedAudioUrl} controls />} </div> ); };
内容的提问来源于stack exchange,提问作者monika mane
相关产品推荐
相关产品推荐

