網路需要更多(有品味的)聲音!
該庫僅適用於 React DOM,但 @remigallego 創建了 React Native 的替代方案!查看react-native-use-sound。
這個專案是「半維護」的?
我現在沒有足夠的資源來研究邊緣問題或幫助排除故障,但我計劃使其與主要 React 版本保持同步,並修復既嚴重又常見的問題。
如果您對功能有想法,或者遇到奇怪的怪癖,我強烈建議您分叉該項目並將其變成您自己的!它可能看起來令人生畏,但原始程式碼並不像許多其他 NPM 套件那麼複雜;我把所有硬音頻工作都交給了 Howler)。如果您已經使用 React 一段時間並且熟悉 hooks,那麼您應該對這個包的程式碼感到熟悉。
可以使用yarn添加包:
yarn add use-sound
或者,使用 NPM:
npm install use-sound
UMD 建置可在 unpkg 上使用。
如果您的專案使用 TypeScript,您還應該安裝@types/howler
套件作為開發依賴項。
該教程包括許多演示,以及查找和準備聲音效果的說明。這是一個很好的起點。
您還可以查看故事書,其中包含許多快速範例。
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` ensures that if the sound starts again before it's
// ended, it will truncate it. Otherwise, the sound can overlap.
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,這將建立一個動態的、可公開存取的檔案路徑。
或者,大多數工具都會為您提供一個「公共」(create-react-app、Next.js)或「靜態」(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
掛鉤的所有選項都是如此。
useSound
掛鉤有兩個參數:
HookOptions
)它產生一個包含兩個值的陣列:
ExposedData
)當呼叫函數播放聲音時,您可以向其傳遞一組選項( PlayOptions
)。
讓我們依序逐一討論。
呼叫useSound
時,您可以向其傳遞多種選項:
姓名 | 價值 |
---|---|
體積 | 數位 |
播放速率 | 數位 |
打斷 | 布林值 |
聲音啟用 | 布林值 |
精靈 | 雪碧圖 |
[委託] | — |
volume
是從0
到1
數字,其中1
是最大音量, 0
是完全靜音。playbackRate
是一個從0.5
到4
數字。它可用於減慢或加速樣品。與轉盤一樣,速度的變化也會影響音高。interrupt
指定如果在聲音結束之前再次呼叫play
函數,聲音是否應該能夠「重疊」。soundEnabled
可讓您傳遞一個值(通常來自上下文或 redux 等)來靜音所有聲音。請注意,這可以在PlayOptions
中覆蓋,請參見下文sprite
允許您使用單一useSound
掛鉤來實現多種聲音效果。請參閱下面的“精靈”。 [delegated]
指的是您在HookOptions
中傳遞的任何附加參數都會被轉送到Howl
建構子。有關詳細信息,請參閱下面的“逃生艙口”。
play
功能呼叫鉤子時,您將傳回一個播放函數作為元組中的第一項:
const [ play ] = useSound ( '/meow.mp3' ) ;
// ^ What we're talking about
當您想要觸發聲音時,可以不帶任何參數來呼叫此函數。您也可以使用PlayOptions
物件來呼叫它:
姓名 | 價值 |
---|---|
ID | 細繩 |
強制聲音啟用 | 布林值 |
播放速率 | 數位 |
id
用於精靈辨識。請參閱下面的“精靈”。forceSoundEnabled
允許您覆寫傳遞給HookOptions
的soundEnabled
布林值。你通常不想這樣做。我發現的唯一例外:在「靜音」按鈕上觸發聲音。playbackRate
是設定新播放速率的另一種方式,與HookOptions
中相同。一般來說,您應該更喜歡透過HookOptions
來完成此操作,這是一個逃脫艙口。此鉤子產生一個包含 2 個選項的元組,即 play 函數和ExposedData
物件:
const [ play , exposedData ] = useSound ( '/meow.mp3' ) ;
// ^ What we're talking about
姓名 | 價值 |
---|---|
停止 | 函數 ((id?: string) => void) |
暫停 | 函數 ((id?: string) => void) |
期間 | 數字(或空白) |
聲音 | 嚎叫(或空) |
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 ended!' ) ;
} ,
} ) ;
如果您需要更多控制,您應該能夠直接使用sound
對象,它是 Howler 的一個實例。
例如:Howler 公開了一個fade
方法,可讓您淡入或淡出聲音。您可以直接在sound
物件上呼叫此方法:
const Arcade = ( ) => {
const [ play , { sound } ] = useSound ( '/win-theme.mp3' ) ;
return (
< button
onClick = { ( ) => {
// You win! Fade in the victory theme
sound . fade ( 0 , 1 , 1000 ) ;
} }
>
Click to win
< / button >
) ;
} ;