使用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會員
10內容數
愛看金庸的阿傑,想來分享一下我看金庸的點點滴滴。 講談金庸小說,免不了要爆一堆雷,所以請尚未看過金庸小說的朋友,跳過這裡,先去看金庸原著,享受金庸的武俠世界,別被爆雷破壞了第一次閱讀金庸小說的樂趣。 至於已看過金庸原著的朋友,歡迎一起分享你的觀點,小說劇情本就會各有解讀,各有領會,這才是現代文學的魅力!
留言0
查看全部
發表第一個留言支持創作者!
Ni 1968的沙龍 的其他內容
如何在 Vite 專案中安裝和設置 TypeScript 及路徑別名的步驟,包括安裝必要的依賴、配置 vite.config.js、tsconfig.json 的設置,及如何創建類型聲明文件來正確識別 .vue 文件。
如何在 Vite 專案中安裝和設置 TypeScript 及路徑別名的步驟,包括安裝必要的依賴、配置 vite.config.js、tsconfig.json 的設置,及如何創建類型聲明文件來正確識別 .vue 文件。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
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
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
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 新增了沙龍功能,目的是為了取代原本的「專題」,我這篇就來分享一下我目前摸索沙龍的經驗