使用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 註冊一次性事件監聽器,只會觸發一次


留言
avatar-img
Ni 1968的沙龍
2會員
12內容數
愛看金庸的阿傑,想來分享一下我看金庸的點點滴滴。 講談金庸小說,免不了要爆一堆雷,所以請尚未看過金庸小說的朋友,跳過這裡,先去看金庸原著,享受金庸的武俠世界,別被爆雷破壞了第一次閱讀金庸小說的樂趣。 至於已看過金庸原著的朋友,歡迎一起分享你的觀點,小說劇情本就會各有解讀,各有領會,這才是現代文學的魅力!
Ni 1968的沙龍的其他內容
2024/12/21
介紹如何使用 JavaScript 中的陣列基本增刪元素方法,包括新增、刪除和替換元素的詳細說明。介紹的主要方法有 unshift、push、shift、pop、splice 和 slice,並解釋它們的使用場景和返回值。
Thumbnail
2024/12/21
介紹如何使用 JavaScript 中的陣列基本增刪元素方法,包括新增、刪除和替換元素的詳細說明。介紹的主要方法有 unshift、push、shift、pop、splice 和 slice,並解釋它們的使用場景和返回值。
Thumbnail
2024/11/02
在 Vue 應用中直接使用 .reverse() 來修改陣列可能在開發環境中未出現問題,但在生產環境中卻可能導致重新渲染錯誤及資料順序不一致的問題。建議使用 .slice() 創建淺拷貝的解決方案,以確保 Vue 的反應性系統能正常運作並避免應用當機。
Thumbnail
2024/11/02
在 Vue 應用中直接使用 .reverse() 來修改陣列可能在開發環境中未出現問題,但在生產環境中卻可能導致重新渲染錯誤及資料順序不一致的問題。建議使用 .slice() 創建淺拷貝的解決方案,以確保 Vue 的反應性系統能正常運作並避免應用當機。
Thumbnail
2024/08/08
如何在 Vite 專案中安裝和設置 TypeScript 及路徑別名的步驟,包括安裝必要的依賴、配置 vite.config.js、tsconfig.json 的設置,及如何創建類型聲明文件來正確識別 .vue 文件。
Thumbnail
2024/08/08
如何在 Vite 專案中安裝和設置 TypeScript 及路徑別名的步驟,包括安裝必要的依賴、配置 vite.config.js、tsconfig.json 的設置,及如何創建類型聲明文件來正確識別 .vue 文件。
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
先前提到 Quasar 的 Dialog Plugin 很好用,再讓我補充一個用法。
Thumbnail
先前提到 Quasar 的 Dialog Plugin 很好用,再讓我補充一個用法。
Thumbnail
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
前言 從零開始構建一個 DateTimePicker 可能看起來令人畏懼,但試想一下你將獲得的靈活性和控制力。在這個系列中,我們將逐步揭開構建過程的神秘面紗,讓您能夠創建一個完全符合需求的自定義 DateTimePicker。 本文章,屬於付費系列的文章,這篇文章,我會希望讀者可以得到的
Thumbnail
前言 從零開始構建一個 DateTimePicker 可能看起來令人畏懼,但試想一下你將獲得的靈活性和控制力。在這個系列中,我們將逐步揭開構建過程的神秘面紗,讓您能夠創建一個完全符合需求的自定義 DateTimePicker。 本文章,屬於付費系列的文章,這篇文章,我會希望讀者可以得到的
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
Swiper.js 是一個功能齊全的輪播套件,除了輪播外,也可以客製化導航按鈕和頁碼等細項。目前支持 JS、React、Vue。但是 Swiper.js Vue 版本主要由 Composition API 風格構成,此篇文章將介紹 Options API 的撰寫方式,以及如何做樣式客製化。
Thumbnail
Swiper.js 是一個功能齊全的輪播套件,除了輪播外,也可以客製化導航按鈕和頁碼等細項。目前支持 JS、React、Vue。但是 Swiper.js Vue 版本主要由 Composition API 風格構成,此篇文章將介紹 Options API 的撰寫方式,以及如何做樣式客製化。
Thumbnail
新增video_player 在pubspec.yaml中加入video_player。 設置權限 Android 在AndroidManifest.xml檔案中的<application>裡,加入下列代碼。 <uses-permission android:name="androi
Thumbnail
新增video_player 在pubspec.yaml中加入video_player。 設置權限 Android 在AndroidManifest.xml檔案中的<application>裡,加入下列代碼。 <uses-permission android:name="androi
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 學習筆記,vue-router 篇。
Thumbnail
Vue3 學習筆記,vue-router 篇。
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News