使用howler.js 在vue頁面播放音效

閱讀時間約 1 分鐘

howler.js是一個強大的 JavaScript 音效庫,可以方便地在網頁上播放音效。

在 Vue.js 中使用 Howler.js 可以輕鬆地管理和播放音效。

  • npm安裝
npm install howler
  • 如果使用Typescript,由於Howler.js 沒有提供內置的 TypeScript 類型定義檔案,所以需要手動為 Howler 添加類型定義。
  1. 在項目根目錄下創建一個 types 文件夾(如果還沒有)。
  2. types 文件夾中創建一個 howler.d.ts 文件。
  3. howler.d.ts 文件中添加以下內容:
declare module 'howler' {
export class Howl {
constructor(options: HowlOptions);
play(sprite?: string | number): number;
pause(id?: number): void;
stop(id?: number): void;
mute(muted?: boolean, id?: number): void;
volume(volume?: number, id?: number): number;
fade(from: number, to: number, duration: number, id?: number): void;
rate(rate?: number, id?: number): number;
seek(seek?: number, id?: number): number;
loop(loop?: boolean, id?: number): boolean;
playing(id?: number): boolean;
duration(id?: number): number;
state(): string;
load(): void;
unload(): void;
on(event: string, handler: (id?: number) => void): void;
off(event: string, handler?: (id?: number) => void): void;
once(event: string, handler: (id?: number) => void): void;
}

export interface HowlOptions {
src: string | string[];
volume?: number;
html5?: boolean;
loop?: boolean;
preload?: boolean;
autoplay?: boolean;
mute?: boolean;
rate?: number;
pool?: number;
format?: string | string[];
xhrWithCredentials?: boolean;
onload?: () => void;
onloaderror?: (id: number, error: any) => void;
onplay?: (id: number) => void;
onend?: (id: number) => void;
onpause?: (id: number) => void;
onstop?: (id: number) => void;
onmute?: (id: number) => void;
onvolume?: (id: number) => void;
onrate?: (id: number) => void;
onseek?: (id: number) => void;
onfade?: (id: number) => void;
onunlock?: (id: number) => void;
}
}
  • 快速使用範例
<script setup lang="ts">
//引入 Howler.js
import { Howl } from 'howler';
//創建 Howl 實例:(此範例是將sample.mp3 放置於public/audio)
const sound = new Howl({ src: ['audio/sample.mp3'] });
//播放音效
const playSound = () => {
sound.play();
}
</script>
  • 基本使用範例
<template>
<div>
<button @click="playSound">播放音效</button>
<button @click="pauseSound">暫停音效</button>
<button @click="stopSound">停止音效</button>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Howl } from 'howler';

// 創建一個 ref 來保存 Howl 實例
const sound = ref<Howl | null>(null);

// 播放音效的方法
const playSound = () => {
if (!sound.value) {
sound.value = new Howl({
src: ['path/audio/sample.mp3']
});
}
sound.value.play();
};

// 暫停音效的方法
const pauseSound = () => {
if (sound.value) {
sound.value.pause();
}
};

// 停止音效的方法
const stopSound = () => {
if (sound.value) {
sound.value.stop();
}
};
</script>


  • 設置音量
const sound = new Howl({
src: ['/audio/sample.mp3'],
volume: 0.5 // 設置音量為 50%
});
  • 全局設置音量(需要引入Howler)
import { Howler } from 'howler';

// 設置全局音量為 50%
Howler.volume(0.5);

引入Howler,之前所提到的howler.d.ts 需要補以下內容

// 新增 Howler 全局對象的聲明
export const Howler: {
volume(volume?: number): number; // 控制全局音量
mute(muted: boolean): void; // 控制全局靜音
codecs(ext: string): boolean; // 檢查瀏覽器支持的音頻格式
stop(): void; // 停止所有音效
unload(): void; // 卸載所有音效
};
  • 控制全局音量範例
<template>
<div>
<button @click="playSound">播放音效</button>
<input type="range" min="0" max="1" step="0.1" v-model="volume"
@input="setGlobalVolume(volume)">
<label>全局音量: {{ volume }}</label>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Howl, Howler } from 'howler';

// 音量狀態,初始值為 0.5
const volume = ref(0.5);

// 用來儲存 Howl 實例的變數
const sound = ref<Howl | null>(null);

// 播放音效的函數
const playSound = () => {
if (!sound.value) {
sound.value = new Howl({
src: ['audio/sample.mp3']
});
}
sound.value.play();
};

// 設置全局音量的函數
const setGlobalVolume = (newVolume: number) => {
Howler.volume(newVolume);
};
</script>
  • 循環播放(加上loop: true ​)
// 播放循環音效的函數
const playLoopingSound = () => {
if (!sound.value) {
sound.value = new Howl({
src: ['path/to/your/audio/file.mp3'],
loop: true,
});
}
sound.value.play();
};
  • 監聽音效事件(onend, onplay, onpause, onstop, onloaderror)
<template>
<div>
<button @click="playSoundWithEvents">播放音效並監聽事件</button>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Howl } from 'howler';

// 儲存 Howl 實例的變數
const sound = ref<Howl | null>(null);

// 播放音效並監聽事件
const playSoundWithEvents = () => {
if (!sound.value) {
sound.value = new Howl({
src: ['audio/sample.mp3'],
onend: () => {
console.log('音效播放完畢');
},
onplay: () => {
console.log('音效開始播放');
},
onpause: () => {
console.log('音效暫停');
},
onstop: () => {
console.log('音效停止');
},
onloaderror: (id, error) => {
console.error('音效加載失敗', error);
}
});
}
sound.value.play();
};
</script>


  • 預加載音效

在 Howler.js 中,音效預加載是默認行為,當創建一個 Howl 實例時,音效文件就會開始加載。

可以通過 autoplay: false(默認)和 preload: true(默認)來控制的。

當 preload 設置為 true 時,音效會在創建 Howl 實例後自動預加載。

可以透過監聽 onload 事件來確定音效是否已經加載完畢。

<template>
<div>
<button @click="playSound" :disabled="!isLoaded">播放音效</button>
<p v-if="!isLoaded">音效加載中...</p>
<p v-if="isLoaded">音效已加載,點擊按鈕播放</p>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Howl } from 'howler';

// 音效加載狀態
const isLoaded = ref(false);

// 用來儲存 Howl 實例的變數
const sound = ref<Howl | null>(null);

// 創建 Howl 實例並預加載音效
sound.value = new Howl({
src: ['audio/sample.mp3'],
preload: true, // 預加載音效(默認是 true)
onload: () => {
isLoaded.value = true; // 當音效加載完畢時設置為 true
console.log('音效已加載');
},
onloaderror: (id, error) => {
console.error('音效加載失敗', error);
}
});

// 播放音效
const playSound = () => {
if (sound.value && isLoaded.value) {
sound.value.play();
}
};
</script>
  • 多個音效預加載
<script setup lang="ts">
import { onMounted } from 'vue';
import { Howl } from 'howler';

// 音效加載狀態
const allLoaded = ref(false);
const sounds: Howl[] = [];

// 在組件加載時預加載所有音效
onMounted(() => {
const soundFiles = [
'audio/1.mp3',
'audio/2.mp3',
'audio/3.mp3'
];

let loadedCount = 0;

soundFiles.forEach((src) => {
const sound = new Howl({
src: [src],
preload: true,
onload: () => {
loadedCount++;
if (loadedCount === soundFiles.length) {
allLoaded.value = true;
console.log('所有音效已加載');
}
},
onloaderror: (id, error) => {
console.error('音效加載失敗', error);
}
});
sounds.push(sound);
});
});
</script>

當所有音效文件都加載完畢時,更新 allLoaded 變數,表示所有音效已經準備好播放。

  • 懶加載
<template>
<div>
<button @click="playSound('audio1')">播放音效 1</button>
<button @click="playSound('audio2')">播放音效 2</button>
<button @click="playSound('audio3')">播放音效 3</button>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Howl } from 'howler';

// 儲存 Howl 實例的對象,按需創建和載入音效
const sounds: { [key: string]: Howl | null } = {
audio1: null,
audio2: null,
audio3: null,
};

// 音效的文件路徑
const soundFiles = {
audio1: 'audio/1.mp3',
audio2: 'audio/2.mp3',
audio3: 'audio/3.mp3',
};

// 播放音效的函數,按需加載音效
const playSound = (name: string) => {
if (!sounds[name]) {
// 懶加載音效:當音效第一次播放時才創建對應的 Howl 實例
sounds[name] = new Howl({
src: [soundFiles[name]],
preload: false, // 延遲加載音效,直到需要播放
onload: () => {
console.log(`${name} 已加載`);
},
onloaderror: (id, error) => {
console.error(`${name} 加載失敗`, error);
}
});
}
// 確保音效已經存在並開始播放
sounds[name]?.play();
};
</script>


  • 使用音效物件方式播放音效
import { Howl } from 'howler';

interface AudioManager {
sounds: { [key: string]: Howl };
preloadAll: () => void;
play: (name: string) => void;
playingBlockInstances: number;
maxBlockInstances: number;
}
const soundMuted = ref(false);
const isStop = ref(false);
const audioManager: AudioManager = {
// 宣告音效物件
sounds: {
error: new Howl({ src: ['/audio/error.mp3'] }),
win: new Howl({ src: ['/audio/win.mp3'] }),
click: new Howl({ src: ['/audio/click.mp3'] })
},
// 預加載
preloadAll() {
Object.values(this.sounds).forEach((sound) => {
sound.load();
});
},

// 播放音效函式
play(name: string) {
if (soundMuted) return;
const sound = this.sounds[name];
if (sound) {
const id = sound.play();
if(isStop.value) {
sound.stop(id);
}
} else {
console.error(`Sound ${name} not found!`);
}
},
};

// 播放音效的物件方法
const playSnd = {
win: () => audioManager.play('win'),
click () => audioManager.play('bet'),
err: () => audioManager.play('error')
};

playSnd.click(); //播放按鈕音效


  • 其他補充

sound.once 註冊一次性事件監聽器,只會觸發一次


1會員
9內容數
愛看金庸的阿傑,想來分享一下我看金庸的點點滴滴。 講談金庸小說,免不了要爆一堆雷,所以請尚未看過金庸小說的朋友,跳過這裡,先去看金庸原著,享受金庸的武俠世界,別被爆雷破壞了第一次閱讀金庸小說的樂趣。 至於已看過金庸原著的朋友,歡迎一起分享你的觀點,小說劇情本就會各有解讀,各有領會,這才是現代文學的魅力!
留言0
查看全部
發表第一個留言支持創作者!
Ni 1968的沙龍 的其他內容
如何在 Vite 專案中安裝和設置 TypeScript 及路徑別名的步驟,包括安裝必要的依賴、配置 vite.config.js、tsconfig.json 的設置,及如何創建類型聲明文件來正確識別 .vue 文件。
如何在 Vite 專案中安裝和設置 TypeScript 及路徑別名的步驟,包括安裝必要的依賴、配置 vite.config.js、tsconfig.json 的設置,及如何創建類型聲明文件來正確識別 .vue 文件。
你可能也想看
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
前言 從零開始構建一個 DateTimePicker 可能看起來令人畏懼,但試想一下你將獲得的靈活性和控制力。在這個系列中,我們將逐步揭開構建過程的神秘面紗,讓您能夠創建一個完全符合需求的自定義 DateTimePicker。 本文章,屬於付費系列的文章,這篇文章,我會希望讀者可以得到的
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
進入Lua的第一步! 安裝和執行
Thumbnail
因為最近想嘗試編碼風格,於是就選了一套比較"不嚴格"的輔助工具來摸索。 編輯器 VS CODE 框架 VUE3 打包工具 VITE 編碼風格 Standard 環境 version { "nodejs":"v18.18.0", "npm":"9.8.1" }
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
這是為了搭建自己想要的工作流而開始的研究工作。
Thumbnail
Vocus 新增了沙龍功能,目的是為了取代原本的「專題」,我這篇就來分享一下我目前摸索沙龍的經驗
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
前言 從零開始構建一個 DateTimePicker 可能看起來令人畏懼,但試想一下你將獲得的靈活性和控制力。在這個系列中,我們將逐步揭開構建過程的神秘面紗,讓您能夠創建一個完全符合需求的自定義 DateTimePicker。 本文章,屬於付費系列的文章,這篇文章,我會希望讀者可以得到的
Thumbnail
你好,在下最近在學習開發web,學了html css js,也得出一些心得,由於網路上已有許多教學,所以我會著重在如何開發出to do List,以及解釋我寫的程式碼。相關的教學我會直接貼網址。如果我有什麼地方出錯,或者是可以寫得更好,歡迎在下方留言,討論。 首先先介紹我的開發環境: 我用了vs
Thumbnail
進入Lua的第一步! 安裝和執行
Thumbnail
因為最近想嘗試編碼風格,於是就選了一套比較"不嚴格"的輔助工具來摸索。 編輯器 VS CODE 框架 VUE3 打包工具 VITE 編碼風格 Standard 環境 version { "nodejs":"v18.18.0", "npm":"9.8.1" }
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
這是為了搭建自己想要的工作流而開始的研究工作。
Thumbnail
Vocus 新增了沙龍功能,目的是為了取代原本的「專題」,我這篇就來分享一下我目前摸索沙龍的經驗