网页需要更多(恰到好处的)声音!
这个库只适用于 React DOM,但 @remigallego 为 React Native 创建了一个替代方案!查看 react-native-use-sound。
这个项目处于"半维护"状态 😅
我目前没有精力去研究边缘情况的问题或帮助排查问题,但我计划随着 React 的主要版本更新来保持项目的更新,并修复那些既严重又常见的问题。
如果你有功能想法,或遇到奇怪的问题,我强烈建议你 fork 这个项目并使其成为你自己的!这可能看起来有点吓人,但源代码并不像其他许多 NPM 包那样复杂;我将所有困难的音频工作都交给了 Howler。如果你已经使用 React 一段时间并且熟悉 hooks,你应该会对这个包的代码感到很熟悉。
可以使用 yarn 添加包:
yarn add use-sound
或者使用 NPM:
npm install use-sound
UMD 构建可在 unpkg 上获得。
如果你的项目使用 TypeScript,你还应该将 @types/howler
包作为开发依赖项安装。
教程 包含了许多演示,以及寻找和准备音效的说明。这是一个很好的起点。
你还可以 查看 storybook,其中包含了许多快速示例。
import useSound from 'use-sound'; import boopSfx from '../../sounds/boop.mp3'; const BoopButton = () => { const [play] = useSound(boopSfx); return <button onClick={play}>Boop!</button>; };
这个演示只在鼠标悬停在元素上时播放声音。当鼠标离开元素时,声音会暂停:
注意:许多浏览器会禁用声音,直到用户在页面上点击某个地方。如果你在这个例子中听不到任何声音,试着在页面上随意点击一下,然后再试一次。
import useSound from 'use-sound'; import fanfareSfx from '../../sounds/fanfare.mp3'; const FanfareButton = () => { const [play, { stop }] = useSound(fanfareSfx); return ( <button onMouseEnter={() => play()} onMouseLeave={() => stop()}> <span role="img" aria-label="trumpet"> 🎺 </span> </button> ); };
使用 playbackRate
选项,你可以改变样本的速度/音调。这个例子播放一个声音,并且每次都让它快 10%:
import useSound from 'use-sound'; import glugSfx from '../../sounds/glug.mp3'; export const RisingPitch = () => { const [playbackRate, setPlaybackRate] = React.useState(0.75); const [play] = useSound(glugSfx, { playbackRate, // `interrupt` 确保如果声音在结束前再次开始, // 它将被截断。否则,声音可能会重叠。 interrupt: true, }); const handleClick = () => { setPlaybackRate(playbackRate + 0.1); play(); }; return ( <Button onClick={handleClick}> <span role="img" aria-label="Person with lines near mouth"> 🗣 </span> </Button> ); };
useSound
需要一个音频文件的路径,但在 React 应用中如何提供这个路径并不是很明显。
使用 create-react-app
,你可以"导入"一个 MP3 文件。它会解析为一个动态生成的路径:
import someAudioFile from '../sounds/sound.mp3'; console.log(someAudioFile); // "/build/sounds/sound-abc123.mp3"
如果你尝试在其他 React 构建系统中使用这个技巧,比如 Next.js,你可能会得到这样的错误:
你可能需要一个适当的加载器来处理这种文件类型,目前没有配置加载器来处理这个文件。
问题在于 Webpack(在底层用于生成 JS 包的打包工具)不知道如何处理 MP3 文件。
如果你可以访问 Webpack 配置,你可以更新它以使用 file-loader,这将创建一个动态的、可公开访问的文件路径。
另外,大多数工具都会给你一个"public"(create-react-app, Next.js)或"static"(Gatsby)文件夹。你可以将音频文件放在那里,然后使用字符串路径。
你将与 use-sound
一起使用的声音文件遵循与其他静态资源(如图像或字体)相同的规则。按照你所选择的元框架的指南:
⚠️ 异步声音路径? ⚠️ 如果你的音频文件的 URL 是异步加载的,你可能会遇到一些问题。这个包可能不适合这种用例。
为了用户着想,浏览器不允许网站在用户与之交互(例如通过点击)之前产生声音。在用户点击、触摸或触发某些操作之前,不会产生声音。
useSound
利用了这一点:因为我们知道在加载后不会立即需要声音,我们可以延迟加载第三方依赖。
useSound
会向你的包中添加约 1kb gzip 大小的代码,并在加载后异步获取一个额外的包,大小约为 9kb gzip。
如果用户恰好在这个依赖被加载和获取之前点击了会产生声音的东西,它将是一个空操作(一切仍然会正常工作,但不会播放音效)。根据我的经验,这种情况 非常罕见。
考虑以下代码片段:
const [playbackRate, setPlaybackRate] = React.useState(0.75); const [play] = useSound('/path/to/sound', { playbackRate });
playbackRate
不仅仅是音效的初始值。如果 playbackRate
改变,声音将立即以新的速率开始播放。这对传递给 useSound
hook 的所有选项都是如此。
useSound
hook 接受两个参数:
HookOptions
)它返回一个包含两个值的数组:
ExposedData
)当调用函数来播放声音时,你可以传递一组选项 (PlayOptions
)。
让我们依次了解每一个。
调用 useSound
时,你可以传递各种选项:
名称 | 值 |
---|---|
volume | number |
playbackRate | number |
interrupt | boolean |
soundEnabled | boolean |
sprite | SpriteMap |
[delegated] | — |
volume
是一个从 0
到 1
的数字,其中 1
是全音量,0
是完全静音。playbackRate
是一个从 0.5
到 4
的数字。它可以用来减慢或加快样本。像唱片机一样,速度的变化也会影响音调。interrupt
指定如果在声音结束前再次调用 play
函数,声音是否应该能够"重叠"。soundEnabled
允许你传递一个值(通常来自 context 或 redux 或其他地方)来静音所有声音。注意,这可以在 PlayOptions
中被覆盖,见下文。sprite
允许你为多个音效使用单个 useSound
hook。参见下面的"Sprites"。[delegated]
指的是你在 HookOptions
中传递的任何额外参数都将被转发到 Howl
构造函数。有关更多信息,请参见下面的"Escape hatches"。
play
函数当调用 hook 时,你会在元组的第一项中得到一个 play 函数:
const [play] = useSound('/meow.mp3'); // ^ 我们正在讨论的内容
当你想触发声音时,你可以不带任何参数调用这个函数。你也可以用一个 PlayOptions
对象来调用它:
名称 | 值 |
---|---|
id | string |
forceSoundEnabled | boolean |
playbackRate | number |
id
用于精灵标识。详见下面的"精灵"部分。forceSoundEnabled
允许你覆盖传递给 HookOptions
的 soundEnabled
布尔值。通常你不会想这样做。我发现唯一的例外是:在"静音"按钮上触发声音。playbackRate
是另一种设置新播放速率的方法,与 HookOptions
中的相同。一般来说,你应该优先通过 HookOptions
来设置,这只是一个后备选项。该钩子产生一个包含两个选项的元组,即播放函数和一个 ExposedData
对象:
const [play, exposedData] = useSound('/meow.mp3'); // ^ 我们正在讨论的内容
名称 | 值 |
---|---|
stop | 函数 ((id?: string) => void) |
pause | 函数 ((id?: string) => void) |
duration | 数字 (或 null) |
sound | Howl (或 null) |
stop
是一个可以用来提前停止声音的函数。pause
类似于 stop
,但可以从同一点恢复。除非你知道要恢复,否则应该使用 stop
;pause
会占用资源,因为它预期在某个时候会恢复。duration
是样本的长度,以毫秒为单位。在样本加载完之前,它将为 null
。注意,对于精灵,它是整个文件的长度。sound
是一个后备选项。它让你访问底层的 Howl
实例。查看 Howler 文档 了解如何使用它。注意,在组件挂载后的最初几个时刻,这将是 null
。音频精灵是一个包含多个样本的单个音频文件。你可以加载一个单独的文件,并将其切分成多个可以独立触发的部分,而不是加载许多单独的声音。
这可能会带来性能优势,因为它减少了并行网络请求,但如果单个组件需要多个样本,这也可能值得这么做。参见 鼓机示例 作为例子。
对于精灵,我们需要定义一个 SpriteMap
。它看起来像这样:
const spriteMap = { laser: [0, 300], explosion: [1000, 300], meow: [2000, 75], };
SpriteMap
是一个对象。键是个别声音的 id
。值是一个包含 2 个项目的元组(固定长度的数组):
这个可视化可能会使它更清晰:
我们可以将 SpriteMap 作为 HookOptions 之一传递:
const [play] = useSound('/path/to/sprite.mp3', { sprite: { laser: [0, 300], explosion: [1000, 300], meow: [2000, 75], }, });
要播放特定的精灵,我们在调用 play
函数时传递其 id
:
<button onClick={() => play({id: 'laser'})} >
Howler 是一个非常强大的库,我们在 useSound
中只暴露了它能做的很小一部分。我们提供两个后备选项来给你更多控制。
首先,你传递给 HookOptions
的任何未识别的选项都将被委托给 Howl
。你可以在 Howler 文档中看到完整列表。这里是一个例子,展示了我们如何使用 onend
在声音停止播放时触发一个函数:
const [play] = useSound('/thing.mp3', { onend: () => { console.info('声音结束了!'); }, });
如果你需要更多控制,你应该能够直接使用 sound
对象,它是 Howler 的一个实例。
例如:Howler 暴露了一个 fade
方法,让你可以淡入或淡出声音。你可以直接在 sound
对象上调用这个方法:
const Arcade = () => { const [play, { sound }] = useSound('/win-theme.mp3'); return ( <button onClick={() => { // 你赢了!淡入胜利 主题 sound.fade(0, 1, 1000); }} > 点击获胜 </button> ); };
AI数字人视频创作平台
Keevx 一款开箱即用的AI数字人视频创作平台,广泛适用于电商广告、企业培训与社媒宣传,让全球企业与个人创作者无需拍摄剪辑,就能快速生成多语言、高质量的专业视频。
一站式AI创作平台
提供 AI 驱动的图片、视频生成及数字人等功能,助力创意创作
AI办公助手,复杂任务高效处理
AI办公助手,复杂任务高效处理。办公效率低?扣子空间AI助手支持播客生成、PPT制作、网页开发及报告写作,覆盖科研、商业、舆情等领域的专家Agent 7x24小时响应,生活工作无缝切换,提升50%效率!
AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
AI小说写作助手,一站式润色、改写、扩写
蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高 效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。