Vue3音頻組件開發(fā)與使用指南(包括播放控制、進度條)
Vue3音頻組件開發(fā)與使用指南
前言
在現(xiàn)代Web應用中,音頻播放功能越來越常見,特別是在娛樂和社交應用中。本文將詳細介紹如何在Vue3項目中開發(fā)一個功能完整的音頻播放組件,包括播放控制、進度條、時間顯示以及多音頻實例管理等功能。
效果

項目結構
src/
├── components/
│ └── audio/
│ └── index.vue # 音頻組件
├── store/
│ └── modules/
│ └── audio.ts # 音頻狀態(tài)管理
└── assets/
└── audio/
├── play.png # 播放按鈕圖標
└── pause.png # 暫停按鈕圖標核心功能特性
- ? 播放/暫停控制
- ? 進度條拖拽調節(jié)
- ? 時間顯示(當前時間/總時長)
- ? 播放速度調節(jié)
- ? 降噪功能
- ? 多音頻實例管理
- ? 禁用狀態(tài)支持
- ? 自定義樣式
音頻狀態(tài)管理 (Pinia Store)
首先,我們使用Pinia來管理全局音頻狀態(tài),確保同時只有一個音頻在播放:
// src/store/modules/audio.ts
import { defineStore } from 'pinia';
type AudioElement = HTMLAudioElement & { uid?: symbol };
export const useAudioStore = defineStore('audio', {
state: () => ({
instances: new Set<AudioElement>(),
currentPlaying: null as AudioElement | null
}),
actions: {
// 注冊音頻實例
register(audio: AudioElement) {
if (!audio.uid) {
audio.uid = Symbol('audio-instance');
}
this.instances.add(audio);
},
// 注銷音頻實例
unregister(audio: AudioElement) {
this.instances.delete(audio);
},
// 暫停除當前音頻外的所有音頻
pauseAllExcept(currentAudio: AudioElement) {
this.instances.forEach(audio => {
if (audio.uid !== currentAudio.uid && !audio.paused) {
audio.pause();
audio.dispatchEvent(new Event('force-pause'));
}
});
this.currentPlaying = currentAudio;
}
}
});狀態(tài)管理設計思路
- 實例管理:使用Set存儲所有音頻實例,避免重復
- 唯一標識:為每個音頻元素分配唯一的Symbol標識
- 互斥播放:確保同時只有一個音頻在播放
- 事件通知:通過自定義事件通知組件狀態(tài)變化
音頻組件實現(xiàn)
組件Props定義
const props = defineProps({
url: String, // 音頻URL
speed: String, // 播放速度
noiseSuppression: Boolean, // 降噪開關
disabled: Boolean, // 禁用狀態(tài)
isbg: String, // 背景樣式
mock: { // 模擬模式
type: Boolean,
default: false,
},
playData: { // 播放數(shù)據(jù)
type: Object,
default: () => ({}),
},
res: { // 響應數(shù)據(jù)
type: String,
default: '',
},
});核心響應式數(shù)據(jù)
const audioPlayer = ref<any>(); // 音頻元素引用
const audioUrl = ref(props.url); // 音頻URL
const progress = ref(0); // 播放進度
const timeCount = ref(0); // 總時長(秒*10)
const startTime = ref('00:00'); // 當前時間
const endTime = ref('00:00'); // 總時長
const isPlay = ref(false); // 播放狀態(tài)關鍵功能實現(xiàn)
1. 播放控制
const playClick = () => {
if (endTime.value == '00:00') return;
if (!audioUrl.value || props.disabled || props.mock) return;
// 暫停其他音頻
if (audioPlayer.value) {
audioStore.pauseAllExcept(audioPlayer.value);
}
startOrStop();
};
const startOrStop = () => {
isPlay.value = !isPlay.value;
emit('playClick', { ...props.playData, isPlay: isPlay.value, res: props.res });
if (isPlay.value) {
audioPlayer.value?.play();
// 啟動進度更新定時器
time.value = setInterval(() => {
progress.value++;
startTime.value = secondToTime(progress.value / 10);
}, 100);
} else {
audioPlayer.value?.pause();
clearInterval(time.value);
clearInterval(time1.value);
}
};2. 進度條控制
// 進度條拖拽中
const proChange = () => {
if (isDown.value) {
clearInterval(time.value);
clearInterval(time1.value);
audioPlayer.value.pause(progress.value / 10);
}
};
// 進度條拖拽結束
const proUp = () => {
isDown.value = false;
audioPlayer.value.currentTime = progress.value / 10;
audioPlayer.value.play();
clearInterval(time.value);
clearInterval(time1.value);
isPlay.value = true;
// 重新啟動進度更新
time1.value = setInterval(() => {
progress.value++;
startTime.value = secondToTime(progress.value / 10);
}, 100);
};3. 時間格式化
const secondToTime = (val: number) => {
if (!isFinite(val)) return '0:00';
val = Math.round(val);
const minutes = Math.floor(val / 60);
const seconds = val % 60;
const secondsStr = seconds < 10 ? `0${seconds}` : seconds;
return `${minutes}:${secondsStr}`;
};4. 生命周期管理
onMounted(() => {
if (audioPlayer.value) {
// 注冊到全局store
audioStore.register(audioPlayer.value);
// 監(jiān)聽外部暫停事件
audioPlayer.value.addEventListener('force-pause', () => {
isPlay.value = false;
clearInterval(time.value);
clearInterval(time1.value);
});
// 初始化音頻時長
if (audioUrl.value) {
playAudio();
}
}
});
onUnmounted(() => {
if (audioPlayer.value) {
audioStore.unregister(audioPlayer.value);
}
});
組件模板結構
<template>
<div>
<div :class="`audio-zj ${(disabled || mock) && 'audio-disabled'} ${isbg ? '' : 'isbg'}`">
<div class="a1">
<!-- 播放/暫停按鈕 -->
<el-image :src="playImg" v-show="isPlay" class="a-icon" @click="playClick"></el-image>
<el-image :src="pauseImg" v-show="!isPlay" class="a-icon" @click="playClick"></el-image>
<!-- 進度條和時間顯示 -->
<div class="t-bottom">
<el-slider
v-model="progress"
:show-tooltip="false"
:max="timeCount"
:disabled="disabled || mock"
class="jindu"
@input="proChange"
@change="proUp"
/>
<span class="already-time">{{ startTime }}/</span>
<span class="total-time">{{ endTime }}</span>
</div>
</div>
<!-- 隱藏的音頻元素 -->
<audio
ref="audioPlayer"
class="audioPlayer"
@timeupdate="timeupdate"
:src="audioUrl"
@loadeddata="onLoad"
@ended="onEnded"
controls
></audio>
</div>
</div>
</template>使用方法
1. 基礎使用
<template>
<div>
<Audio :url="audioUrl" />
</div>
</template>
<script setup>
import Audio from '@/components/audio/index.vue';
const audioUrl = ref('https://example.com/audio.mp3');
</script>2. 完整配置
<template>
<Audio
:url="item.files.url"
:speed="playbackSpeed"
:noise-suppression="true"
:disabled="isDisabled"
:mock="isMockMode"
:play-data="playData"
:res="responseData"
@play-click="handlePlayClick"
@on-load="handleAudioLoad"
@on-ended="handleAudioEnd"
/>
</template>
<script setup>
const playData = ref({
id: 'audio-1',
title: '音頻標題'
});
const handlePlayClick = (data) => {
console.log('播放狀態(tài)變化:', data);
};
const handleAudioLoad = () => {
console.log('音頻加載完成');
};
const handleAudioEnd = () => {
console.log('音頻播放結束');
};
</script>樣式定制
組件提供了豐富的CSS類名供自定義樣式:
.audio-zj {
// 進度條樣式定制
.jindu {
.el-slider__button {
background: #f68842 !important;
border: solid 2px #f68842;
width: 11px;
height: 11px;
}
.el-slider__bar {
background-color: #f68842;
height: 3px;
}
}
// 禁用狀態(tài)樣式
&.audio-disabled {
cursor: not-allowed;
.a-icon {
opacity: 0.5;
}
}
}高級特性
1. 多音頻管理
通過Pinia store實現(xiàn)全局音頻管理,確保用戶體驗:
// 播放新音頻時自動暫停其他音頻 audioStore.pauseAllExcept(audioPlayer.value);
2. 播放速度控制
watch(
() => props.speed,
newVal => {
if (audioPlayer.value) {
audioPlayer.value.playbackRate = newVal;
}
},
);3. 降噪功能
watch(
() => props.noiseSuppression,
newVal => {
if (audioPlayer.value) {
audioPlayer.value.noiseSuppression = newVal;
}
},
);最佳實踐
- 性能優(yōu)化:使用定時器更新進度時注意清理,避免內存泄漏
- 用戶體驗:同時只允許一個音頻播放,避免聲音沖突
- 錯誤處理:對音頻加載失敗、網(wǎng)絡異常等情況進行處理
- 響應式設計:確保組件在不同設備上的顯示效果
- 無障礙訪問:添加適當?shù)腁RIA標簽和鍵盤導航支持
總結
本文介紹的Vue3音頻組件具有以下優(yōu)勢:
- ?? 功能完整:涵蓋播放控制、進度管理、時間顯示等核心功能
- ?? 高度可配置:支持多種配置選項和自定義樣式
- ?? 性能優(yōu)秀:合理的狀態(tài)管理和生命周期處理
- ?? 用戶友好:直觀的界面設計和流暢的交互體驗
- ?? 穩(wěn)定可靠:完善的錯誤處理和邊界情況考慮
這個組件可以直接應用到各種需要音頻播放功能的Vue3項目中,為用戶提供優(yōu)質的音頻播放體驗。
到此這篇關于Vue3音頻組件開發(fā)與使用指南(包括播放控制、進度條)的文章就介紹到這了,更多相關vue音頻組件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue登錄頁面回車執(zhí)行事件@keyup.enter.native問題
這篇文章主要介紹了vue登錄頁面回車執(zhí)行事件@keyup.enter.native問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
Vue3中如何使用v-model高級用法參數(shù)綁定傳值
本文給大家介紹Vue3中使用v-model高級用法參數(shù)綁定傳值的相關知識,包括單個輸入框傳值和多個輸入框傳值,一個組件接受多個v-model值,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2023-10-10
vue中動態(tài)修改animation效果無效問題詳情
這篇文章主要介紹了vue中動態(tài)修改animation效果無效問題詳情,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-06-06

