音频初始化&实例销毁
概述
本节深入 Howler.js 的核心 API,包括 Howl 和 Howler 两个对象的使用,音频实例的创建、配置、播放控制和销毁。
Howler.js 核心对象
Howl vs Howler
| 对象 | 类型 | 作用 |
|---|---|---|
Howl | 构造函数 | 创建单个音频实例,提供播放控制方法 |
Howler | 全局对象 | 管理全局配置(编解码器检测、自动解锁、主音量等) |
import { Howl, Howler } from 'howler'
// Howler: 全局配置
Howler.volume(0.5) // 设置全局音量
Howler.mute(false) // 取消全局静音
Howler.autoUnlock = true // 自动解锁音频(移动端)
Howler.html5PoolSize = 10 // HTML5 Audio 池大小
// Howl: 实例化音频
const sound = new Howl({
src: ['audio.mp3', 'audio.webm'],
volume: 1.0,
loop: false,
rate: 1.0,
autoplay: false
})
typescript
音频实例初始化
基础用法
import { Howl } from 'howler'
interface AudioOptions {
src: string | string[]
autoplay?: boolean
loop?: boolean
volume?: number
rate?: number
html5?: boolean
preload?: boolean
}
function createAudioInstance(options: AudioOptions): Howl {
return new Howl({
src: options.src,
autoplay: options.autoplay ?? false,
loop: options.loop ?? false,
volume: options.volume ?? 1.0,
rate: options.rate ?? 1.0,
html5: options.html5 ?? false,
preload: options.preload ?? true,
// 事件回调
onload() {
console.log('音频加载完成')
},
onloaderror(_, error) {
console.error('加载失败:', error)
},
onplay() {
console.log('开始播放')
},
onpause() {
console.log('暂停播放')
},
onstop() {
console.log('停止播放')
},
onend() {
console.log('播放结束')
}
})
}
typescript
HTML5 模式 vs Web Audio 模式
| 特性 | Web Audio(默认) | HTML5 Audio |
|---|---|---|
| 音频格式 | 解码到内存 | 流式播放 |
| 大文件支持 | 不适合(内存占用大) | 适合(stream 模式) |
| 延迟 | 低延迟 | 略高延迟 |
| 兼容性 | 现代浏览器 | 所有浏览器 |
| 多音源 | 支持 | 受限(池大小限制) |
// 大文件使用 HTML5 模式
const podcast = new Howl({
src: ['podcast.mp3'],
html5: true // 流式加载,不预解码
})
typescript
音频精灵(Audio Sprite)
// 将多个音效合并为一个文件,按片段播放
const soundSprite = new Howl({
src: ['sounds.webm', 'sounds.mp3'],
sprite: {
click: [0, 300], // 0ms 开始,持续 300ms
hover: [400, 200], // 400ms 开始,持续 200ms
success: [700, 800], // 700ms 开始,持续 800ms
error: [1600, 600] // 1600ms 开始,持续 600ms
}
})
// 播放精灵中的某个片段
soundSprite.play('click')
typescript
Vue 组件中的集成
// 在 AudioPlayer 组件中管理实例
import { ref, onBeforeMount, onUnmounted } from 'vue'
import { Howl, Howler } from 'howler'
const audioInstance = ref<Howl | null>(null)
function initAudio(src: string | string[], options?: Partial<HowlOptions>) {
// 销毁旧实例
if (audioInstance.value) {
audioInstance.value.unload()
}
audioInstance.value = new Howl({
src: Array.isArray(src) ? src : [src],
...options,
onload() {
state.duration = audioInstance.value!.duration()
options?.onload?.()
},
onplay(id) {
state.playing = true
// 启动进度更新定时器
startProgressTimer(id)
options?.onplay?.(id)
},
onpause() {
state.playing = false
stopProgressTimer()
options?.onpause?.()
},
onstop() {
state.playing = false
state.progress = 0
stopProgressTimer()
options?.onstop?.()
},
onend() {
state.playing = false
state.progress = 0
stopProgressTimer()
options?.onend?.()
}
})
}
// 实例销毁
onBeforeMount(() => {
if (audioInstance.value) {
audioInstance.value.unload()
audioInstance.value = null
}
})
// 页面卸载时销毁所有实例
onUnmounted(() => {
Howler.unload() // 销毁页面上所有的 Howl 实例
})
typescript
进度更新机制
let progressTimer: ReturnType<typeof requestAnimationFrame> | null = null
function startProgressTimer(soundId: number) {
const update = () => {
if (audioInstance.value && state.playing) {
state.progress = audioInstance.value.seek(soundId) as number
progressTimer = requestAnimationFrame(update)
}
}
progressTimer = requestAnimationFrame(update)
}
function stopProgressTimer() {
if (progressTimer) {
cancelAnimationFrame(progressTimer)
progressTimer = null
}
}
typescript
常用 Howl 方法速查
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
play() | sprite/id | soundId | 播放,返回声音 ID |
pause(id?) | soundId | Howl | 暂停 |
stop(id?) | soundId | Howl | 停止(重置 seek) |
seek(time?, id?) | 秒数, soundId | number/Howl | 获取/设置播放位置 |
volume(vol?, id?) | 0-1, soundId | number/Howl | 获取/设置音量 |
rate(rate?, id?) | 0.5-4, soundId | number/Howl | 获取/设置速率 |
loop(loop?, id?) | boolean, soundId | boolean/Howl | 获取/设置循环 |
mute(muted?, id?) | boolean, soundId | Howl | 静音控制 |
duration() | - | number | 获取总时长 |
unload() | - | void | 销毁实例释放资源 |
小结
Howl是音频实例构造函数,Howler是全局管理对象- 默认使用 Web Audio API,大文件建议开启
html5: true流式加载 - 音频精灵(Sprite)可将多个音效合并为一个文件按片段播放
- 组件卸载时务必调用
unload()销毁实例释放资源 - 使用
requestAnimationFrame实现流畅的进度条更新
↑